diff options
Diffstat (limited to 'vendor/modernc.org/cc/v3')
25 files changed, 31319 insertions, 0 deletions
diff --git a/vendor/modernc.org/cc/v3/AUTHORS b/vendor/modernc.org/cc/v3/AUTHORS new file mode 100644 index 00000000..53046c0d --- /dev/null +++ b/vendor/modernc.org/cc/v3/AUTHORS @@ -0,0 +1,19 @@ +# This file lists authors for copyright purposes. This file is distinct from +# the CONTRIBUTORS files. See the latter for an explanation. +# +# Names should be added to this file as: +# Name or Organization <email address> +# +# The email address is not required for organizations. +# +# Please keep the list sorted. + +Dan Kortschak <dan.kortschak@adelaide.edu.au> +Dan Peterson <danp@danp.net> +Denys Smirnov <denis.smirnov.91@gmail.com> +Jan Mercl <0xjnml@gmail.com> +Maxim Kupriianov <max@kc.vc> +Peter Waller <p@pwaller.net> +Steffen Butzer <steffen(dot)butzer@outlook.com> +Tommi Virtanen <tv@eagain.net> +Yasuhiro Matsumoto <mattn.jp@gmail.com> diff --git a/vendor/modernc.org/cc/v3/CONTRIBUTORS b/vendor/modernc.org/cc/v3/CONTRIBUTORS new file mode 100644 index 00000000..69eb75cc --- /dev/null +++ b/vendor/modernc.org/cc/v3/CONTRIBUTORS @@ -0,0 +1,18 @@ +# This file lists people who contributed code to this repository. The AUTHORS +# file lists the copyright holders; this file lists people. +# +# Names should be added to this file like so: +# Name <email address> +# +# Please keep the list sorted. + +Dan Kortschak <dan.kortschak@adelaide.edu.au> +Dan Peterson <danp@danp.net> +Denys Smirnov <denis.smirnov.91@gmail.com> +Jan Mercl <0xjnml@gmail.com> +Maxim Kupriianov <max@kc.vc> +Peter Waller <p@pwaller.net> +Steffen Butzer <steffen(dot)butzer@outlook.com> +Tommi Virtanen <tv@eagain.net> +Yasuhiro Matsumoto <mattn.jp@gmail.com> +Zvi Effron <zeffron@cs.hmc.edu> diff --git a/vendor/modernc.org/cc/v3/GO-LICENSE b/vendor/modernc.org/cc/v3/GO-LICENSE new file mode 100644 index 00000000..6a66aea5 --- /dev/null +++ b/vendor/modernc.org/cc/v3/GO-LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/modernc.org/cc/v3/LICENSE b/vendor/modernc.org/cc/v3/LICENSE new file mode 100644 index 00000000..0f98cdb8 --- /dev/null +++ b/vendor/modernc.org/cc/v3/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2017 The CC Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the names of the authors nor the names of the +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/modernc.org/cc/v3/Makefile b/vendor/modernc.org/cc/v3/Makefile new file mode 100644 index 00000000..af921559 --- /dev/null +++ b/vendor/modernc.org/cc/v3/Makefile @@ -0,0 +1,124 @@ +# 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. + +.PHONY: all bench clean cover cpu editor internalError later mem nuke todo edit devbench + +grep=--include=*.go --include=*.l --include=*.y --include=*.yy +ngrep='internalError\|TODOOK\|lexer\.go\|ast.go\|trigraphs\.go\|.*_string\.go\|stringer\.go\|testdata\/gcc' +testlog=testdata/testlog-$(shell echo $$GOOS)-$(shell echo $$GOARCH)-on-$(shell go env GOOS)-$(shell go env GOARCH) + +all: lexer.go + LC_ALL=C make all_log 2>&1 | tee log + +all_log: + date + go version + uname -a + ./unconvert.sh + gofmt -l -s -w *.go + GOOS=darwin GOARCH=amd64 go build + GOOS=darwin GOARCH=arm64 go build + GOOS=linux GOARCH=386 go build + GOOS=linux GOARCH=amd64 go build + GOOS=linux GOARCH=arm go build + GOOS=windows GOARCH=386 go build + GOOS=windows GOARCH=amd64 go build + go vet | grep -v $(ngrep) || true + golint | grep -v $(ngrep) || true + misspell *.go + staticcheck | grep -v 'lexer\.go' || true + pcregrep -nM 'FAIL|false|<nil>|:\n}' ast_test.go || true + +test: + go version | tee $(testlog) + uname -a | tee -a $(testlog) + go test -v -timeout 24h | tee -a $(testlog) + grep -ni fail $(testlog) | tee -a $(testlog) || true + LC_ALL=C date | tee -a $(testlog) + grep -ni --color=always fail $(testlog) || true + +test_linux_amd64: + GOOS=linux GOARCH=amd64 make test + +test_linux_386: + GOOS=linux GOARCH=386 make test + +test_linux_arm: + GOOS=linux GOARCH=arm make test + +test_linux_arm64: + GOOS=linux GOARCH=arm64 make test + +test_windows_amd64: + go version + go test -v -timeout 24h + +test_windows386: + go version + go test -v -timeout 24h + +build_all_targets: + GOOS=darwin GOARCH=amd64 go build -v ./... + GOOS=darwin GOARCH=arm64 go build -v ./... + GOOS=freebsd GOARCH=amd64 go build -v ./... + GOOS=freebsd GOARCH=386 go build -v ./... + GOOS=linux GOARCH=386 go build -v ./... + GOOS=linux GOARCH=amd64 go build -v ./... + GOOS=linux GOARCH=arm go build -v ./... + GOOS=linux GOARCH=arm64 go build -v ./... + GOOS=netbsd GOARCH=amd64 go build -v ./... + GOOS=windows GOARCH=386 go build -v ./... + GOOS=windows GOARCH=amd64 go build -v ./... + +devbench: + date 2>&1 | tee log-devbench + go test -timeout 24h -dev -run @ -bench . 2>&1 | tee -a log-devbench + grep -n 'FAIL\|SKIP' log-devbench || true + +bench: + date 2>&1 | tee log-bench + go test -timeout 24h -v -run '^[^E]' -bench . 2>&1 | tee -a log-bench + grep -n 'FAIL\|SKIP' log-bench || true + +clean: + go clean + rm -f *~ *.test *.out + +cover: + t=$(shell mktemp) ; go test -coverprofile $$t && go tool cover -html $$t && unlink $$t + +cpu: clean + go test -run @ -bench . -cpuprofile cpu.out + go tool pprof -lines *.test cpu.out + +edit: + @touch log + @if [ -f "Session.vim" ]; then gvim -S & else gvim -p Makefile *.go & fi + +editor: lexer.go + gofmt -l -s -w *.go + go test -o /dev/null -c + go install 2>&1 | tee log + +ast.go lexer.go stringer.go: lexer.l parser.yy enum.go + go generate + +later: + @grep -n $(grep) LATER * || true + @grep -n $(grep) MAYBE * || true + +mem: clean + # go test -v -run ParserCS -csmith 2m -memprofile mem.out -timeout 24h + # go test -v -run @ -bench BenchmarkScanner -memprofile mem.out -timeout 24h + go test -v -run TestTranslateSQLite -memprofile mem.out -timeout 24h + go tool pprof -lines -web -alloc_space *.test mem.out + +nuke: clean + go clean -i + +todo: + @grep -nr $(grep) ^[[:space:]]*_[[:space:]]*=[[:space:]][[:alpha:]][[:alnum:]]* * | grep -v $(ngrep) || true + @grep -nr $(grep) 'TODO\|panic' * | grep -v $(ngrep) || true + @grep -nr $(grep) BUG * | grep -v $(ngrep) || true + @grep -nr $(grep) [^[:alpha:]]println * | grep -v $(ngrep) || true diff --git a/vendor/modernc.org/cc/v3/README.md b/vendor/modernc.org/cc/v3/README.md new file mode 100644 index 00000000..c330c799 --- /dev/null +++ b/vendor/modernc.org/cc/v3/README.md @@ -0,0 +1,11 @@ +# cc/v3 + +Package CC is a C99 compiler front end. + +Most of the functionality is now working. + +Installation + + $ go get -u modernc.org/cc/v3 + +Documentation: [godoc.org/modernc.org/cc/v3](http://godoc.org/modernc.org/cc/v3) diff --git a/vendor/modernc.org/cc/v3/abi.go b/vendor/modernc.org/cc/v3/abi.go new file mode 100644 index 00000000..e0325584 --- /dev/null +++ b/vendor/modernc.org/cc/v3/abi.go @@ -0,0 +1,1022 @@ +// 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 ( + "encoding/binary" + "fmt" + "math" + "os" + "runtime" + + "lukechampine.com/uint128" + "modernc.org/mathutil" +) + +var ( + idAligned = String("aligned") + idGCCStruct = String("gcc_struct") + idMSStruct = String("ms_struct") + idPacked = String("packed") + + complexTypedefs = map[StringID]Kind{ + dict.sid("__COMPLEX_CHAR_TYPE__"): ComplexChar, + dict.sid("__COMPLEX_DOUBLE_TYPE__"): ComplexDouble, + dict.sid("__COMPLEX_FLOAT_TYPE__"): ComplexFloat, + dict.sid("__COMPLEX_INT_TYPE__"): ComplexInt, + dict.sid("__COMPLEX_LONG_TYPE__"): ComplexLong, + dict.sid("__COMPLEX_LONG_DOUBLE_TYPE__"): ComplexLongDouble, + dict.sid("__COMPLEX_LONG_LONG_TYPE__"): ComplexLongLong, + dict.sid("__COMPLEX_SHORT_TYPE__"): ComplexShort, + dict.sid("__COMPLEX_UNSIGNED_TYPE__"): ComplexUInt, + dict.sid("__COMPLEX_LONG_UNSIGNED_TYPE__"): ComplexULong, + dict.sid("__COMPLEX_LONG_LONG_UNSIGNED_TYPE__"): ComplexULongLong, + dict.sid("__COMPLEX_SHORT_UNSIGNED_TYPE__"): ComplexUShort, + } +) + +// NewABI creates an ABI for a given OS and architecture. The OS and architecture values are the same as used in Go. +// The ABI type map may miss advanced types like complex numbers, etc. If the os/arch pair is not recognized, a +// *ErrUnsupportedOSArch is returned. +func NewABI(os, arch string) (ABI, error) { + order, ok := abiByteOrders[arch] + if !ok { + return ABI{}, fmt.Errorf("unsupported arch: %s", arch) + } + types, ok := abiTypes[[2]string{os, arch}] + if !ok { + return ABI{}, fmt.Errorf("unsupported os/arch pair: %s-%s", os, arch) + } + abi := ABI{ + ByteOrder: order, + Types: make(map[Kind]ABIType, len(types)), + SignedChar: abiSignedChar[[2]string{os, arch}], + os: os, + arch: arch, + } + // copy the map, so it can be modified by user + for k, v := range types { + abi.Types[k] = v + } + return abi, nil +} + +// NewABIFromEnv uses GOOS and GOARCH values to create a corresponding ABI. +// If those environment variables are not set, an OS/arch of a Go runtime is used. +// It returns a *ErrUnsupportedOSArch if OS/arch pair is not supported. +func NewABIFromEnv() (ABI, error) { + osv := os.Getenv("GOOS") + if osv == "" { + osv = runtime.GOOS + } + arch := os.Getenv("GOARCH") + if arch == "" { + arch = runtime.GOARCH + } + return NewABI(osv, arch) +} + +// ABIType describes properties of a non-aggregate type. +type ABIType struct { + Size uintptr + Align int + FieldAlign int +} + +// ABI describes selected parts of the Application Binary Interface. +type ABI struct { + ByteOrder binary.ByteOrder + Types map[Kind]ABIType + arch string + os string + types map[Kind]Type + + SignedChar bool +} + +func (a *ABI) sanityCheck(ctx *context, intMaxWidth int, s Scope) error { + if intMaxWidth == 0 { + intMaxWidth = 64 + } + + a.types = map[Kind]Type{} + for _, k := range []Kind{ + Bool, + Char, + Double, + Enum, + Float, + Int, + Long, + LongDouble, + LongLong, + Ptr, + SChar, + Short, + UChar, + UInt, + ULong, + ULongLong, + UShort, + Void, + } { + v, ok := a.Types[k] + if !ok { + if ctx.err(noPos, "ABI is missing %s", k) { + return ctx.Err() + } + + continue + } + + if (k != Void && v.Size == 0) || v.Align == 0 || v.FieldAlign == 0 || + v.Align > math.MaxUint8 || v.FieldAlign > math.MaxUint8 { + if ctx.err(noPos, "invalid ABI type %s: %+v", k, v) { + return ctx.Err() + } + } + + if integerTypes[k] && v.Size > 8 { + if ctx.err(noPos, "invalid ABI type %s size: %v, must be <= 8", k, v.Size) { + return ctx.Err() + } + } + var f flag + if integerTypes[k] && a.isSignedInteger(k) { + f = fSigned + } + t := &typeBase{ + align: byte(a.align(k)), + fieldAlign: byte(a.fieldAlign(k)), + flags: f, + kind: byte(k), + size: uintptr(a.size(k)), + } + a.types[k] = t + } + if _, ok := a.Types[Int128]; ok { + t := &typeBase{ + align: byte(a.align(Int128)), + fieldAlign: byte(a.fieldAlign(Int128)), + flags: fSigned, + kind: byte(Int128), + size: uintptr(a.size(Int128)), + } + a.types[Int128] = t + } + if _, ok := a.Types[UInt128]; ok { + t := &typeBase{ + align: byte(a.align(UInt128)), + fieldAlign: byte(a.fieldAlign(UInt128)), + kind: byte(UInt128), + size: uintptr(a.size(UInt128)), + } + a.types[UInt128] = t + } + return ctx.Err() +} + +func (a *ABI) Type(k Kind) Type { return a.types[k] } + +func (a *ABI) align(k Kind) int { return a.Types[k].Align } +func (a *ABI) fieldAlign(k Kind) int { return a.Types[k].FieldAlign } +func (a *ABI) size(k Kind) int { return int(a.Types[k].Size) } + +func (a *ABI) isSignedInteger(k Kind) bool { + if !integerTypes[k] { + internalError() + } + + switch k { + case Bool, UChar, UInt, ULong, ULongLong, UShort: + return false + case Char: + return a.SignedChar + default: + return true + } +} + +func roundup(n, to int64) int64 { + if r := n % to; r != 0 { + return n + to - r + } + + return n +} + +func roundup128(n uint128.Uint128, to uint64) uint128.Uint128 { + if r := n.Mod(uint128.From64(to)); !r.IsZero() { + return n.Add64(to).Sub(r) + } + + return n +} + +func rounddown(n, to int64) int64 { + return n &^ (to - 1) +} + +func rounddown128(n uint128.Uint128, to uint64) uint128.Uint128 { + return n.And(uint128.Uint128{Hi: ^uint64(0), Lo: ^(to - 1)}) +} + +func normalizeBitFieldWidth(n byte) byte { + switch { + case n <= 8: + return 8 + case n <= 16: + return 16 + case n <= 32: + return 32 + case n <= 64: + return 64 + default: + panic(todo("internal error: %v", n)) + } +} + +func (a *ABI) layout(ctx *context, n Node, t *structType) *structType { + if t == nil { + return nil + } + + if t.typeBase.align < 1 { + t.typeBase.align = 1 + } + for _, v := range t.attr { + if _, ok := v.Has(idGCCStruct); ok { + return a.gccLayout(ctx, n, t) + } + + //TODO if _, ok := v.Has(idMSStruct); ok { + //TODO return a.msLayout(ctx, n, t) + //TODO } + } + + switch { + case ctx.cfg.Config3.GCCStructs: + return a.gccLayout(ctx, n, t) + //TODO case ctx.cfg.Config3.MSStructs: + //TODO return a.msLayout(ctx, n, t) + } + + var hasBitfields bool + + defer func() { + if !hasBitfields { + return + } + + m := make(map[uintptr][]*field, len(t.fields)) + for _, f := range t.fields { + off := f.offset + m[off] = append(m[off], f) + } + for _, s := range m { + var first *field + var w byte + for _, f := range s { + if first == nil { + first = f + } + if f.isBitField { + n := f.bitFieldOffset + f.bitFieldWidth + if n > w { + w = n + } + } + } + w = normalizeBitFieldWidth(w) + for _, f := range s { + if f.isBitField { + f.blockStart = first + f.blockWidth = w + } + if a.ByteOrder == binary.BigEndian { + f.bitFieldOffset = w - f.bitFieldWidth - f.bitFieldOffset + f.bitFieldMask = (uint64(1)<<f.bitFieldWidth - 1) << f.bitFieldOffset + } + } + } + }() + + var off int64 // bit offset + align := int(t.typeBase.align) + + switch { + case t.Kind() == Union: + for _, f := range t.fields { + ft := f.Type() + sz := ft.Size() + if n := int64(8 * sz); n > off { + off = n + } + al := ft.FieldAlign() + if al == 0 { + al = 1 + } + if al > align { + align = al + } + + if f.isBitField { + hasBitfields = true + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + } + f.promote = integerPromotion(a, ft) + } + t.align = byte(align) + t.fieldAlign = byte(align) + off = roundup(off, 8*int64(align)) + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + default: + var i int + var group byte + var f, lf *field + for i, f = range t.fields { + ft := f.Type() + var sz uintptr + switch { + case ft.Kind() == Array && i == len(t.fields)-1: + if ft.IsIncomplete() || ft.Len() == 0 { + t.hasFlexibleMember = true + f.isFlexible = true + break + } + + fallthrough + default: + sz = ft.Size() + } + + bitSize := 8 * int(sz) + al := ft.FieldAlign() + if al == 0 { + al = 1 + } + if al > align { + align = al + } + + switch { + case f.isBitField: + hasBitfields = true + eal := 8 * al + if eal < bitSize { + eal = bitSize + } + down := off &^ (int64(eal) - 1) + bitoff := off - down + downMax := off &^ (int64(bitSize) - 1) + skip := lf != nil && lf.isBitField && lf.bitFieldWidth == 0 || + lf != nil && lf.bitFieldWidth == 0 && ctx.cfg.NoFieldAndBitfieldOverlap + switch { + case skip || int(off-downMax)+int(f.bitFieldWidth) > bitSize: + group = 0 + off = roundup(off, 8*int64(al)) + f.offset = uintptr(off >> 3) + f.bitFieldOffset = 0 + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + off += int64(f.bitFieldWidth) + if f.bitFieldWidth == 0 { + lf = f + continue + } + default: + f.offset = uintptr(down >> 3) + f.bitFieldOffset = byte(bitoff) + f.bitFieldMask = (1<<f.bitFieldWidth - 1) << byte(bitoff) + off += int64(f.bitFieldWidth) + } + group += f.bitFieldWidth + default: + if n := group % 64; n != 0 { + group -= n + off += int64(normalizeBitFieldWidth(group) - group) + } + off0 := off + off = roundup(off, 8*int64(al)) + f.pad = byte(off-off0) >> 3 + f.offset = uintptr(off) >> 3 + off += 8 * int64(sz) + group = 0 + } + f.promote = integerPromotion(a, ft) + lf = f + } + t.align = byte(align) + t.fieldAlign = byte(align) + off0 := off + off = roundup(off, 8*int64(align)) + if f != nil && !f.IsBitField() { + f.pad = byte(off-off0) >> 3 + } + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + } + return t +} + +func (a *ABI) Ptr(n Node, t Type) Type { + base := t.base() + base.align = byte(a.align(Ptr)) + base.fieldAlign = byte(a.fieldAlign(Ptr)) + base.kind = byte(Ptr) + base.size = uintptr(a.size(Ptr)) + base.flags &^= fIncomplete + return &pointerType{ + elem: t, + typeBase: base, + } +} + +func (a *ABI) gccLayout(ctx *context, n Node, t *structType) (r *structType) { + if t.IsPacked() { + return a.gccPackedLayout(ctx, n, t) + } + + if t.Kind() == Union { + var off uint128.Uint128 // In bits. + align := int(t.typeBase.align) + for _, f := range t.fields { + switch { + case f.isBitField: + f.offset = 0 + f.bitFieldOffset = 0 + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + if uint64(f.bitFieldWidth) > off.Lo { + off.Lo = uint64(f.bitFieldWidth) + } + default: + al := f.Type().Align() + if al > align { + align = al + } + f.offset = 0 + off2 := uint128.From64(uint64(f.Type().Size())).Mul64(8) + if off2.Cmp(off) > 0 { + off = off2 + } + } + f.promote = integerPromotion(a, f.Type()) + } + t.align = byte(align) + t.fieldAlign = byte(align) + off = roundup128(off, 8*uint64(align)) + t.size = uintptr(off.Rsh(3).Lo) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t + } + + var off uint128.Uint128 // In bits. + align := int(t.typeBase.align) + for i, f := range t.fields { + switch { + case f.isBitField: + al := f.Type().Align() + + // http://jkz.wtf/bit-field-packing-in-gcc-and-clang + + // 1. Jump backwards to nearest address that would support this type. For + // example if we have an int jump to the closest address where an int could be + // stored according to the platform alignment rules. + down := rounddown128(off, 8*uint64(al)) + + // 2. Get sizeof(current field) bytes from that address. + alloc := int64(f.Type().Size()) * 8 + need := int64(f.bitFieldWidth) + if need == 0 && i != 0 { + off = roundup128(off, 8*uint64(al)) + continue + } + + if al > align { + align = al + } + used := int64(off.Sub(down).Lo) + switch { + case alloc-used >= need: + // 3. If the number of bits that we need to store can be stored in these bits, + // put the bits in the lowest possible bits of this block. + off = down.Add64(uint64(used)) + f.offset = uintptr(down.Rsh(3).Lo) + f.bitFieldOffset = byte(used) + f.bitFieldMask = (1<<f.bitFieldWidth - 1) << used + off = off.Add64(uint64(f.bitFieldWidth)) + f.promote = integerPromotion(a, f.Type()) + default: + // 4. Otherwise, pad the rest of this block with zeros, and store the bits that + // make up this bit-field in the lowest bits of the next block. + off = roundup128(off, 8*uint64(al)) + f.offset = uintptr(off.Rsh(3).Lo) + f.bitFieldOffset = 0 + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + off = off.Add64(uint64(f.bitFieldWidth)) + f.promote = integerPromotion(a, f.Type()) + } + default: + al := f.Type().Align() + if al > align { + align = al + } + off = roundup128(off, 8*uint64(al)) + f.offset = uintptr(off.Rsh(3).Lo) + sz := uint128.From64(uint64(f.Type().Size())) + off = off.Add(sz.Mul64(8)) + f.promote = integerPromotion(a, f.Type()) + } + } + var lf *field + for _, f := range t.fields { + if lf != nil && !lf.isBitField && !f.isBitField { + lf.pad = byte(f.offset - lf.offset - lf.Type().Size()) + } + lf = f + } + t.align = byte(align) + t.fieldAlign = byte(align) + off0 := off + off = roundup128(off, 8*uint64(align)) + if lf != nil && !lf.IsBitField() { + lf.pad = byte(off.Sub(off0).Rsh(3).Lo) + } + t.size = uintptr(off.Rsh(3).Lo) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t +} + +func (a *ABI) gccPackedLayout(ctx *context, n Node, t *structType) (r *structType) { + switch a.arch { + case "arm", "arm64": + return a.gccPackedLayoutARM(ctx, n, t) + } + + if t.typeBase.flags&fAligned == 0 { + t.align = 1 + } + t.fieldAlign = t.align + if t.Kind() == Union { + var off int64 // In bits. + for _, f := range t.fields { + switch { + case f.isBitField: + panic(todo("%v: ", n.Position())) + default: + f.offset = 0 + if off2 := 8 * int64(f.Type().Size()); off2 > off { + off = off2 + } + f.promote = integerPromotion(a, f.Type()) + } + } + off = roundup(off, 8) + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t + } + + var off int64 // In bits. + for i, f := range t.fields { + switch { + case f.isBitField: + if f.bitFieldWidth == 0 { + if i != 0 { + off = roundup(off, 8*int64(f.Type().Align())) + } + continue + } + + if b := f.Type().base(); b.flags&fAligned != 0 { + off = roundup(off, 8*int64(a.Types[f.Type().Kind()].Align)) + } + f.offset = uintptr(off >> 3) + f.bitFieldOffset = byte(off & 7) + f.bitFieldMask = (1<<f.bitFieldWidth - 1) << f.bitFieldOffset + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + default: + al := f.Type().Align() + off = roundup(off, 8*int64(al)) + f.offset = uintptr(off) >> 3 + off += 8 * int64(f.Type().Size()) + f.promote = integerPromotion(a, f.Type()) + } + } + var lf *field + for _, f := range t.fields { + if lf != nil && !lf.isBitField && !f.isBitField { + lf.pad = byte(f.offset - lf.offset - lf.Type().Size()) + } + lf = f + } + off0 := off + off = roundup(off, 8*int64(t.Align())) + if lf != nil && !lf.IsBitField() { + lf.pad = byte(off-off0) >> 3 + } + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t +} + +func (a *ABI) gccPackedLayoutARM(ctx *context, n Node, t *structType) (r *structType) { + align := 1 + if t.typeBase.flags&fAligned == 0 { + t.align = 1 + } + t.fieldAlign = t.align + if t.Kind() == Union { + var off int64 // In bits. + for _, f := range t.fields { + switch { + case f.isBitField: + panic(todo("%v: ", n.Position())) + default: + f.offset = 0 + if off2 := 8 * int64(f.Type().Size()); off2 > off { + off = off2 + } + f.promote = integerPromotion(a, f.Type()) + } + } + off = roundup(off, 8) + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t + } + + var off int64 // In bits. + for i, f := range t.fields { + switch { + case f.isBitField: + if f.bitFieldWidth == 0 { + al := f.Type().Align() + if al > align { + align = al + } + if i != 0 { + off = roundup(off, 8*int64(f.Type().Align())) + } + continue + } + + if b := f.Type().base(); b.flags&fAligned != 0 { + off = roundup(off, 8*int64(a.Types[f.Type().Kind()].Align)) + } + f.offset = uintptr(off >> 3) + f.bitFieldOffset = byte(off & 7) + f.bitFieldMask = (1<<f.bitFieldWidth - 1) << f.bitFieldOffset + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + default: + al := f.Type().Align() + off = roundup(off, 8*int64(al)) + f.offset = uintptr(off) >> 3 + off += 8 * int64(f.Type().Size()) + f.promote = integerPromotion(a, f.Type()) + } + } + var lf *field + for _, f := range t.fields { + if lf != nil && !lf.isBitField && !f.isBitField { + lf.pad = byte(f.offset - lf.offset - lf.Type().Size()) + } + lf = f + } + if b := t.base(); b.flags&fAligned == 0 { + t.align = byte(align) + t.fieldAlign = byte(align) + } + off0 := off + off = roundup(off, 8*int64(t.Align())) + if lf != nil && !lf.IsBitField() { + lf.pad = byte(off-off0) >> 3 + } + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t +} + +// https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#x86-Options +// +// -mno-ms-bitfields +// +// Enable/disable bit-field layout compatible with the native Microsoft Windows +// compiler. +// +// If packed is used on a structure, or if bit-fields are used, it may be that +// the Microsoft ABI lays out the structure differently than the way GCC +// normally does. Particularly when moving packed data between functions +// compiled with GCC and the native Microsoft compiler (either via function +// call or as data in a file), it may be necessary to access either format. +// +// This option is enabled by default for Microsoft Windows targets. This +// behavior can also be controlled locally by use of variable or type +// attributes. For more information, see x86 Variable Attributes and x86 Type +// Attributes. +// +// The Microsoft structure layout algorithm is fairly simple with the exception +// of the bit-field packing. The padding and alignment of members of structures +// and whether a bit-field can straddle a storage-unit boundary are determine +// by these rules: +// +// Structure members are stored sequentially in the order in which they are +// declared: the first member has the lowest memory address and the last member +// the highest. Every data object has an alignment requirement. The alignment +// requirement for all data except structures, unions, and arrays is either the +// size of the object or the current packing size (specified with either the +// aligned attribute or the pack pragma), whichever is less. For structures, +// unions, and arrays, the alignment requirement is the largest alignment +// requirement of its members. Every object is allocated an offset so that: +// offset % alignment_requirement == 0 Adjacent bit-fields are packed into the +// same 1-, 2-, or 4-byte allocation unit if the integral types are the same +// size and if the next bit-field fits into the current allocation unit without +// crossing the boundary imposed by the common alignment requirements of the +// bit-fields. MSVC interprets zero-length bit-fields in the following ways: +// +// If a zero-length bit-field is inserted between two bit-fields that are +// normally coalesced, the bit-fields are not coalesced. For example: +// +// struct +// { +// unsigned long bf_1 : 12; +// unsigned long : 0; +// unsigned long bf_2 : 12; +// } t1; +// +// The size of t1 is 8 bytes with the zero-length bit-field. If the zero-length +// bit-field were removed, t1’s size would be 4 bytes. +// +// If a zero-length bit-field is inserted after a bit-field, foo, and the +// alignment of the zero-length bit-field is greater than the member that +// follows it, bar, bar is aligned as the type of the zero-length bit-field. +// For example: +// +// struct +// { +// char foo : 4; +// short : 0; +// char bar; +// } t2; +// +// struct +// { +// char foo : 4; +// short : 0; +// double bar; +// } t3; +// +// For t2, bar is placed at offset 2, rather than offset 1. Accordingly, the +// size of t2 is 4. For t3, the zero-length bit-field does not affect the +// alignment of bar or, as a result, the size of the structure. +// +// Taking this into account, it is important to note the following: +// +// If a zero-length bit-field follows a normal bit-field, the type of the +// zero-length bit-field may affect the alignment of the structure as whole. +// For example, t2 has a size of 4 bytes, since the zero-length bit-field +// follows a normal bit-field, and is of type short. Even if a zero-length +// bit-field is not followed by a normal bit-field, it may still affect the +// alignment of the structure: +// +// struct +// { +// char foo : 6; +// long : 0; +// } t4; +// +// Here, t4 takes up 4 bytes. +// +// Zero-length bit-fields following non-bit-field members are ignored: +// +// struct +// { +// char foo; +// long : 0; +// char bar; +// } t5; +// +// Here, t5 takes up 2 bytes. + +func (a *ABI) msLayout(ctx *context, n Node, t *structType) (r *structType) { + if t.IsPacked() { + return a.msPackedLayout(ctx, n, t) + } + + if t.Kind() == Union { + panic(todo("")) + } + + var off int64 // In bits. + align := int(t.typeBase.align) + var prev *field + for i, f := range t.fields { + switch { + case f.isBitField: + al := f.Type().Align() + if prev != nil { + switch { + case prev.isBitField && prev.Type().Size() != f.Type().Size(): + off = roundup(off, 8*int64(prev.Type().Align())) + off = roundup(off, 8*int64(al)) + case !prev.isBitField: + off = roundup(off, 8*int64(al)) + default: + // Adjacent bit-fields are packed into the same 1-, 2-, or 4-byte allocation + // unit if the integral types are the same size and if the next bit-field fits + // into the current allocation unit without crossing the boundary imposed by + // the common alignment requirements of the bit-fields. + } + } + + // http://jkz.wtf/bit-field-packing-in-gcc-and-clang + + // 1. Jump backwards to nearest address that would support this type. For + // example if we have an int jump to the closest address where an int could be + // stored according to the platform alignment rules. + down := rounddown(off, 8*int64(al)) + + // 2. Get sizeof(current field) bytes from that address. + alloc := int64(f.Type().Size()) * 8 + need := int64(f.bitFieldWidth) + if need == 0 && i != 0 { + off = roundup(off, 8*int64(al)) + continue + } + + if al > align { + align = al + } + used := off - down + switch { + case alloc-used >= need: + // 3. If the number of bits that we need to store can be stored in these bits, + // put the bits in the lowest possible bits of this block. + off = down + used + f.offset = uintptr(down >> 3) + f.bitFieldOffset = byte(used) + f.bitFieldMask = (1<<f.bitFieldWidth - 1) << used + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + default: + // 4. Otherwise, pad the rest of this block with zeros, and store the bits that + // make up this bit-field in the lowest bits of the next block. + off = roundup(off, 8*int64(al)) + f.offset = uintptr(off >> 3) + f.bitFieldOffset = 0 + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + } + default: + if prev != nil && prev.isBitField { + off = roundup(off, 8*int64(prev.Type().Align())) + } + al := f.Type().Align() + if al > align { + align = al + } + off = roundup(off, 8*int64(al)) + f.offset = uintptr(off) >> 3 + off += 8 * int64(f.Type().Size()) + f.promote = integerPromotion(a, f.Type()) + } + prev = f + } + var lf *field + for _, f := range t.fields { + if lf != nil && !lf.isBitField && !f.isBitField { + lf.pad = byte(f.offset - lf.offset - lf.Type().Size()) + } + lf = f + } + t.align = byte(align) + t.fieldAlign = byte(align) + off0 := off + off = roundup(off, 8*int64(align)) + if lf != nil && !lf.IsBitField() { + lf.pad = byte(off-off0) >> 3 + } + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t +} + +func (a *ABI) msPackedLayout(ctx *context, n Node, t *structType) (r *structType) { + if t.typeBase.flags&fAligned == 0 { + t.align = 1 + } + t.fieldAlign = t.align + if t.Kind() == Union { + panic(todo("")) + var off int64 // In bits. + for _, f := range t.fields { + switch { + case f.isBitField: + panic(todo("%v: ", n.Position())) + default: + f.offset = 0 + if off2 := 8 * int64(f.Type().Size()); off2 > off { + off = off2 + } + f.promote = integerPromotion(a, f.Type()) + } + } + off = roundup(off, 8) + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t + } + + var off int64 // In bits. + var prev *field + align := int(t.typeBase.align) + for i, f := range t.fields { + out: + switch { + case f.isBitField: + al := f.Type().Align() + switch { + case prev != nil && prev.IsBitField() && prev.Type().Size() != f.Type().Size(): + off = mathutil.MaxInt64(off, int64(prev.Offset()*8)+int64(prev.BitFieldOffset()+8*prev.Type().Align())) + off = roundup(off, 8*int64(align)) + f.offset = uintptr(off >> 3) + f.bitFieldOffset = 0 + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + break out + } + + // http://jkz.wtf/bit-field-packing-in-gcc-and-clang + + // 1. Jump backwards to nearest address that would support this type. For + // example if we have an int jump to the closest address where an int could be + // stored according to the platform alignment rules. + down := rounddown(off, 8*int64(al)) + + // 2. Get sizeof(current field) bytes from that address. + alloc := int64(f.Type().Size()) * 8 + need := int64(f.bitFieldWidth) + if need == 0 && i != 0 { + off = roundup(off, 8*int64(al)) + continue + } + + used := off - down + switch { + case alloc-used >= need: + // 3. If the number of bits that we need to store can be stored in these bits, + // put the bits in the lowest possible bits of this block. + off = down + used + f.offset = uintptr(down >> 3) + f.bitFieldOffset = byte(used) + f.bitFieldMask = (1<<f.bitFieldWidth - 1) << used + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + default: + // 4. Otherwise, pad the rest of this block with zeros, and store the bits that + // make up this bit-field in the lowest bits of the next block. + off = roundup(off, 8*int64(al)) + f.offset = uintptr(off >> 3) + f.bitFieldOffset = 0 + f.bitFieldMask = 1<<f.bitFieldWidth - 1 + off += int64(f.bitFieldWidth) + f.promote = integerPromotion(a, f.Type()) + } + default: + off = roundup(off, 8) + f.offset = uintptr(off) >> 3 + off += 8 * int64(f.Type().Size()) + f.promote = integerPromotion(a, f.Type()) + } + prev = f + } + var lf *field + for _, f := range t.fields { + if lf != nil && !lf.isBitField && !f.isBitField { + lf.pad = byte(f.offset - lf.offset - lf.Type().Size()) + } + lf = f + } + t.align = byte(align) + t.fieldAlign = byte(align) + switch { + case lf != nil && lf.IsBitField(): + off = mathutil.MaxInt64(off, int64(lf.Offset()*8)+int64(lf.BitFieldOffset()+8*lf.Type().Align())) + off = roundup(off, 8*int64(align)) + default: + off0 := off + off = roundup(off, 8*int64(align)) + if lf != nil && !lf.IsBitField() { + lf.pad = byte(off-off0) >> 3 + } + } + t.size = uintptr(off >> 3) + ctx.structs[StructInfo{Size: t.size, Align: t.Align()}] = struct{}{} + return t +} diff --git a/vendor/modernc.org/cc/v3/abi_platforms.go b/vendor/modernc.org/cc/v3/abi_platforms.go new file mode 100644 index 00000000..24c8d762 --- /dev/null +++ b/vendor/modernc.org/cc/v3/abi_platforms.go @@ -0,0 +1,490 @@ +package cc + +import "encoding/binary" + +// abiByteOrders contains byte order information for known architectures. +var ( + abiByteOrders = map[string]binary.ByteOrder{ + "amd64": binary.LittleEndian, + "386": binary.LittleEndian, + "arm": binary.LittleEndian, + "arm64": binary.LittleEndian, + "s390x": binary.BigEndian, + } + + abiSignedChar = map[[2]string]bool{ + {"linux", "arm"}: false, + {"linux", "arm64"}: false, + {"linux", "s390x"}: false, + + {"darwin", "amd64"}: true, + {"darwin", "arm64"}: true, + {"freebsd", "amd64"}: true, + {"freebsd", "386"}: true, + {"linux", "386"}: true, + {"linux", "amd64"}: true, + {"netbsd", "amd64"}: true, + {"openbsd", "amd64"}: true, + {"windows", "386"}: true, + {"windows", "amd64"}: true, + } +) + +// abiTypes contains size and alignment information for known OS/arch pairs. +// +// The content is generated by ./cmd/cabi/main.c. +var abiTypes = map[[2]string]map[Kind]ABIType{ + // Linux, generated by GCC 8.3.0 + {"linux", "amd64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + Float32: {4, 4, 4}, + Float32x: {8, 8, 8}, + Float64: {8, 8, 8}, + Float64x: {16, 16, 16}, + Float128: {16, 16, 16}, + Decimal32: {4, 4, 4}, + Decimal64: {8, 8, 8}, + Decimal128: {16, 16, 16}, + }, + {"linux", "386"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {4, 4, 4}, + ULong: {4, 4, 4}, + LongLong: {8, 4, 4}, + ULongLong: {8, 4, 4}, + Ptr: {4, 4, 4}, + Function: {4, 4, 4}, + Float: {4, 4, 4}, + Double: {8, 4, 4}, + LongDouble: {12, 4, 4}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 4, 4}, + UInt64: {8, 4, 4}, + Float32: {4, 4, 4}, + Float32x: {8, 4, 4}, + Float64: {8, 4, 4}, + Float64x: {12, 4, 4}, + Float128: {16, 16, 16}, + Decimal32: {4, 4, 4}, + Decimal64: {8, 8, 8}, + Decimal128: {16, 16, 16}, + }, + {"linux", "arm"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {4, 4, 4}, + ULong: {4, 4, 4}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {4, 4, 4}, + Function: {4, 4, 4}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {8, 8, 8}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + }, + {"linux", "arm64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + }, + // $ x86_64-w64-mingw32-gcc main.c && wine a.exe + {"windows", "amd64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {4, 4, 4}, + ULong: {4, 4, 4}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + Float32: {4, 4, 4}, + Float32x: {8, 8, 8}, + Float64: {8, 8, 8}, + Float64x: {16, 16, 16}, + Float128: {16, 16, 16}, + Decimal32: {4, 4, 4}, + Decimal64: {8, 8, 8}, + Decimal128: {16, 16, 16}, + }, + // $ i686-w64-mingw32-gcc main.c && wine a.exe + {"windows", "386"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {4, 4, 4}, + ULong: {4, 4, 4}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {4, 4, 4}, + Function: {4, 4, 4}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {12, 4, 4}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Float32: {4, 4, 4}, + Float32x: {8, 8, 8}, + Float64: {8, 8, 8}, + Float64x: {12, 4, 4}, + Float128: {16, 16, 16}, + Decimal32: {4, 4, 4}, + Decimal64: {8, 8, 8}, + Decimal128: {16, 16, 16}, + }, + {"darwin", "amd64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + }, + {"darwin", "arm64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {8, 8, 8}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + }, + // gcc (SUSE Linux) 7.5.0 + {"linux", "s390x"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 8, 8}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 8, 8}, + UInt128: {16, 8, 8}, + Float32: {4, 4, 4}, + Float32x: {8, 8, 8}, + Float64: {8, 8, 8}, + Float64x: {16, 8, 8}, + Float128: {16, 8, 8}, + Decimal32: {4, 4, 4}, + Decimal64: {8, 8, 8}, + Decimal128: {16, 8, 8}, + }, + // gcc (FreeBSD Ports Collection) 10.3.0 + {"freebsd", "amd64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + }, + // gcc (FreeBSD Ports Collection) 10.3.0 + {"freebsd", "386"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {4, 4, 4}, + ULong: {4, 4, 4}, + LongLong: {8, 4, 4}, + ULongLong: {8, 4, 4}, + Ptr: {4, 4, 4}, + Function: {4, 4, 4}, + Float: {4, 4, 4}, + Double: {8, 4, 4}, + LongDouble: {12, 4, 4}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 4, 4}, + UInt64: {8, 4, 4}, + Float32: {4, 4, 4}, + Float32x: {8, 4, 4}, + Float64: {8, 4, 4}, + Float64x: {16, 16, 16}, + Float128: {16, 16, 16}, + }, + // gcc (GCC) 8.4.0 + {"openbsd", "amd64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + Float32: {4, 4, 4}, + Float32x: {8, 8, 8}, + Float64: {8, 8, 8}, + Float64x: {16, 16, 16}, + Float128: {16, 16, 16}, + }, + // gcc (GCC) 10.3.0 + {"netbsd", "amd64"}: { + Void: {1, 1, 1}, + Bool: {1, 1, 1}, + Char: {1, 1, 1}, + SChar: {1, 1, 1}, + UChar: {1, 1, 1}, + Short: {2, 2, 2}, + UShort: {2, 2, 2}, + Enum: {4, 4, 4}, + Int: {4, 4, 4}, + UInt: {4, 4, 4}, + Long: {8, 8, 8}, + ULong: {8, 8, 8}, + LongLong: {8, 8, 8}, + ULongLong: {8, 8, 8}, + Ptr: {8, 8, 8}, + Function: {8, 8, 8}, + Float: {4, 4, 4}, + Double: {8, 8, 8}, + LongDouble: {16, 16, 16}, + Int8: {1, 1, 1}, + UInt8: {1, 1, 1}, + Int16: {2, 2, 2}, + UInt16: {2, 2, 2}, + Int32: {4, 4, 4}, + UInt32: {4, 4, 4}, + Int64: {8, 8, 8}, + UInt64: {8, 8, 8}, + Int128: {16, 16, 16}, + UInt128: {16, 16, 16}, + }, +} diff --git a/vendor/modernc.org/cc/v3/ast.go b/vendor/modernc.org/cc/v3/ast.go new file mode 100644 index 00000000..7cd777a6 --- /dev/null +++ b/vendor/modernc.org/cc/v3/ast.go @@ -0,0 +1,5232 @@ +// Code generated by yy. DO NOT EDIT. + +// 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 ( + "fmt" + + "modernc.org/token" +) + +// AbstractDeclaratorCase represents case numbers of production AbstractDeclarator +type AbstractDeclaratorCase int + +// Values of type AbstractDeclaratorCase +const ( + AbstractDeclaratorPtr AbstractDeclaratorCase = iota + AbstractDeclaratorDecl +) + +// String implements fmt.Stringer +func (n AbstractDeclaratorCase) String() string { + switch n { + case AbstractDeclaratorPtr: + return "AbstractDeclaratorPtr" + case AbstractDeclaratorDecl: + return "AbstractDeclaratorDecl" + default: + return fmt.Sprintf("AbstractDeclaratorCase(%v)", int(n)) + } +} + +// AbstractDeclarator represents data reduced by productions: +// +// AbstractDeclarator: +// Pointer // Case AbstractDeclaratorPtr +// | Pointer DirectAbstractDeclarator // Case AbstractDeclaratorDecl +type AbstractDeclarator struct { + typ Type + Case AbstractDeclaratorCase `PrettyPrint:"stringer,zero"` + DirectAbstractDeclarator *DirectAbstractDeclarator + Pointer *Pointer +} + +// String implements fmt.Stringer. +func (n *AbstractDeclarator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AbstractDeclarator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.Pointer.Position() + case 1: + if p := n.Pointer.Position(); p.IsValid() { + return p + } + + return n.DirectAbstractDeclarator.Position() + default: + panic("internal error") + } +} + +// AdditiveExpressionCase represents case numbers of production AdditiveExpression +type AdditiveExpressionCase int + +// Values of type AdditiveExpressionCase +const ( + AdditiveExpressionMul AdditiveExpressionCase = iota + AdditiveExpressionAdd + AdditiveExpressionSub +) + +// String implements fmt.Stringer +func (n AdditiveExpressionCase) String() string { + switch n { + case AdditiveExpressionMul: + return "AdditiveExpressionMul" + case AdditiveExpressionAdd: + return "AdditiveExpressionAdd" + case AdditiveExpressionSub: + return "AdditiveExpressionSub" + default: + return fmt.Sprintf("AdditiveExpressionCase(%v)", int(n)) + } +} + +// AdditiveExpression represents data reduced by productions: +// +// AdditiveExpression: +// MultiplicativeExpression // Case AdditiveExpressionMul +// | AdditiveExpression '+' MultiplicativeExpression // Case AdditiveExpressionAdd +// | AdditiveExpression '-' MultiplicativeExpression // Case AdditiveExpressionSub +type AdditiveExpression struct { + lexicalScope Scope + Operand Operand + promote Type + IsSideEffectsFree bool + AdditiveExpression *AdditiveExpression + Case AdditiveExpressionCase `PrettyPrint:"stringer,zero"` + MultiplicativeExpression *MultiplicativeExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *AdditiveExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AdditiveExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1, 2: + if p := n.AdditiveExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.MultiplicativeExpression.Position() + case 0: + return n.MultiplicativeExpression.Position() + default: + panic("internal error") + } +} + +// AlignmentSpecifierCase represents case numbers of production AlignmentSpecifier +type AlignmentSpecifierCase int + +// Values of type AlignmentSpecifierCase +const ( + AlignmentSpecifierAlignasType AlignmentSpecifierCase = iota + AlignmentSpecifierAlignasExpr +) + +// String implements fmt.Stringer +func (n AlignmentSpecifierCase) String() string { + switch n { + case AlignmentSpecifierAlignasType: + return "AlignmentSpecifierAlignasType" + case AlignmentSpecifierAlignasExpr: + return "AlignmentSpecifierAlignasExpr" + default: + return fmt.Sprintf("AlignmentSpecifierCase(%v)", int(n)) + } +} + +// AlignmentSpecifier represents data reduced by productions: +// +// AlignmentSpecifier: +// "_Alignas" '(' TypeName ')' // Case AlignmentSpecifierAlignasType +// | "_Alignas" '(' ConstantExpression ')' // Case AlignmentSpecifierAlignasExpr +type AlignmentSpecifier struct { + Case AlignmentSpecifierCase `PrettyPrint:"stringer,zero"` + ConstantExpression *ConstantExpression + Token Token + Token2 Token + Token3 Token + TypeName *TypeName +} + +// String implements fmt.Stringer. +func (n *AlignmentSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AlignmentSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.ConstantExpression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + default: + panic("internal error") + } +} + +// AndExpressionCase represents case numbers of production AndExpression +type AndExpressionCase int + +// Values of type AndExpressionCase +const ( + AndExpressionEq AndExpressionCase = iota + AndExpressionAnd +) + +// String implements fmt.Stringer +func (n AndExpressionCase) String() string { + switch n { + case AndExpressionEq: + return "AndExpressionEq" + case AndExpressionAnd: + return "AndExpressionAnd" + default: + return fmt.Sprintf("AndExpressionCase(%v)", int(n)) + } +} + +// AndExpression represents data reduced by productions: +// +// AndExpression: +// EqualityExpression // Case AndExpressionEq +// | AndExpression '&' EqualityExpression // Case AndExpressionAnd +type AndExpression struct { + Operand Operand + promote Type + IsSideEffectsFree bool + AndExpression *AndExpression + Case AndExpressionCase `PrettyPrint:"stringer,zero"` + EqualityExpression *EqualityExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *AndExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AndExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.AndExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.EqualityExpression.Position() + case 0: + return n.EqualityExpression.Position() + default: + panic("internal error") + } +} + +// ArgumentExpressionList represents data reduced by productions: +// +// ArgumentExpressionList: +// AssignmentExpression +// | ArgumentExpressionList ',' AssignmentExpression +type ArgumentExpressionList struct { + ArgumentExpressionList *ArgumentExpressionList + AssignmentExpression *AssignmentExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *ArgumentExpressionList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ArgumentExpressionList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.AssignmentExpression.Position() +} + +// Asm represents data reduced by production: +// +// Asm: +// "__asm__" AsmQualifierList '(' STRINGLITERAL AsmArgList ')' +type Asm struct { + AsmArgList *AsmArgList + AsmQualifierList *AsmQualifierList + Token Token + Token2 Token + Token3 Token + Token4 Token +} + +// String implements fmt.Stringer. +func (n *Asm) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Asm) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.AsmQualifierList.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.AsmArgList.Position(); p.IsValid() { + return p + } + + return n.Token4.Position() +} + +// AsmArgList represents data reduced by productions: +// +// AsmArgList: +// ':' AsmExpressionList +// | AsmArgList ':' AsmExpressionList +type AsmArgList struct { + AsmArgList *AsmArgList + AsmExpressionList *AsmExpressionList + Token Token +} + +// String implements fmt.Stringer. +func (n *AsmArgList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmArgList) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.AsmExpressionList.Position() +} + +// AsmExpressionList represents data reduced by productions: +// +// AsmExpressionList: +// AsmIndex AssignmentExpression +// | AsmExpressionList ',' AsmIndex AssignmentExpression +type AsmExpressionList struct { + AsmExpressionList *AsmExpressionList + AsmIndex *AsmIndex + AssignmentExpression *AssignmentExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *AsmExpressionList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmExpressionList) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.AsmIndex.Position(); p.IsValid() { + return p + } + + return n.AssignmentExpression.Position() +} + +// AsmFunctionDefinition represents data reduced by production: +// +// AsmFunctionDefinition: +// DeclarationSpecifiers Declarator AsmStatement +type AsmFunctionDefinition struct { + AsmStatement *AsmStatement + DeclarationSpecifiers *DeclarationSpecifiers + Declarator *Declarator +} + +// String implements fmt.Stringer. +func (n *AsmFunctionDefinition) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmFunctionDefinition) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.DeclarationSpecifiers.Position(); p.IsValid() { + return p + } + + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + return n.AsmStatement.Position() +} + +// AsmIndex represents data reduced by production: +// +// AsmIndex: +// '[' Expression ']' +type AsmIndex struct { + Expression *Expression + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *AsmIndex) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmIndex) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() +} + +// AsmQualifierCase represents case numbers of production AsmQualifier +type AsmQualifierCase int + +// Values of type AsmQualifierCase +const ( + AsmQualifierVolatile AsmQualifierCase = iota + AsmQualifierInline + AsmQualifierGoto +) + +// String implements fmt.Stringer +func (n AsmQualifierCase) String() string { + switch n { + case AsmQualifierVolatile: + return "AsmQualifierVolatile" + case AsmQualifierInline: + return "AsmQualifierInline" + case AsmQualifierGoto: + return "AsmQualifierGoto" + default: + return fmt.Sprintf("AsmQualifierCase(%v)", int(n)) + } +} + +// AsmQualifier represents data reduced by productions: +// +// AsmQualifier: +// "volatile" // Case AsmQualifierVolatile +// | "inline" // Case AsmQualifierInline +// | "goto" // Case AsmQualifierGoto +type AsmQualifier struct { + Case AsmQualifierCase `PrettyPrint:"stringer,zero"` + Token Token +} + +// String implements fmt.Stringer. +func (n *AsmQualifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmQualifier) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Token.Position() +} + +// AsmQualifierList represents data reduced by productions: +// +// AsmQualifierList: +// AsmQualifier +// | AsmQualifierList AsmQualifier +type AsmQualifierList struct { + AsmQualifier *AsmQualifier + AsmQualifierList *AsmQualifierList +} + +// String implements fmt.Stringer. +func (n *AsmQualifierList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmQualifierList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.AsmQualifier.Position() +} + +// AsmStatement represents data reduced by production: +// +// AsmStatement: +// Asm AttributeSpecifierList ';' +type AsmStatement struct { + Asm *Asm + AttributeSpecifierList *AttributeSpecifierList + Token Token +} + +// String implements fmt.Stringer. +func (n *AsmStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AsmStatement) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Asm.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + return n.Token.Position() +} + +// AssignmentExpressionCase represents case numbers of production AssignmentExpression +type AssignmentExpressionCase int + +// Values of type AssignmentExpressionCase +const ( + AssignmentExpressionCond AssignmentExpressionCase = iota + AssignmentExpressionAssign + AssignmentExpressionMul + AssignmentExpressionDiv + AssignmentExpressionMod + AssignmentExpressionAdd + AssignmentExpressionSub + AssignmentExpressionLsh + AssignmentExpressionRsh + AssignmentExpressionAnd + AssignmentExpressionXor + AssignmentExpressionOr +) + +// String implements fmt.Stringer +func (n AssignmentExpressionCase) String() string { + switch n { + case AssignmentExpressionCond: + return "AssignmentExpressionCond" + case AssignmentExpressionAssign: + return "AssignmentExpressionAssign" + case AssignmentExpressionMul: + return "AssignmentExpressionMul" + case AssignmentExpressionDiv: + return "AssignmentExpressionDiv" + case AssignmentExpressionMod: + return "AssignmentExpressionMod" + case AssignmentExpressionAdd: + return "AssignmentExpressionAdd" + case AssignmentExpressionSub: + return "AssignmentExpressionSub" + case AssignmentExpressionLsh: + return "AssignmentExpressionLsh" + case AssignmentExpressionRsh: + return "AssignmentExpressionRsh" + case AssignmentExpressionAnd: + return "AssignmentExpressionAnd" + case AssignmentExpressionXor: + return "AssignmentExpressionXor" + case AssignmentExpressionOr: + return "AssignmentExpressionOr" + default: + return fmt.Sprintf("AssignmentExpressionCase(%v)", int(n)) + } +} + +// AssignmentExpression represents data reduced by productions: +// +// AssignmentExpression: +// ConditionalExpression // Case AssignmentExpressionCond +// | UnaryExpression '=' AssignmentExpression // Case AssignmentExpressionAssign +// | UnaryExpression "*=" AssignmentExpression // Case AssignmentExpressionMul +// | UnaryExpression "/=" AssignmentExpression // Case AssignmentExpressionDiv +// | UnaryExpression "%=" AssignmentExpression // Case AssignmentExpressionMod +// | UnaryExpression "+=" AssignmentExpression // Case AssignmentExpressionAdd +// | UnaryExpression "-=" AssignmentExpression // Case AssignmentExpressionSub +// | UnaryExpression "<<=" AssignmentExpression // Case AssignmentExpressionLsh +// | UnaryExpression ">>=" AssignmentExpression // Case AssignmentExpressionRsh +// | UnaryExpression "&=" AssignmentExpression // Case AssignmentExpressionAnd +// | UnaryExpression "^=" AssignmentExpression // Case AssignmentExpressionXor +// | UnaryExpression "|=" AssignmentExpression // Case AssignmentExpressionOr +type AssignmentExpression struct { + Operand Operand + InitializerOperand Operand // When the expression is used in an initializer + lexicalScope Scope + promote Type + IsSideEffectsFree bool + AssignmentExpression *AssignmentExpression + Case AssignmentExpressionCase `PrettyPrint:"stringer,zero"` + ConditionalExpression *ConditionalExpression + Token Token + UnaryExpression *UnaryExpression +} + +// String implements fmt.Stringer. +func (n *AssignmentExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AssignmentExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.ConditionalExpression.Position() + case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11: + if p := n.UnaryExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.AssignmentExpression.Position() + default: + panic("internal error") + } +} + +// AtomicTypeSpecifier represents data reduced by production: +// +// AtomicTypeSpecifier: +// "_Atomic" '(' TypeName ')' +type AtomicTypeSpecifier struct { + list []*TypeSpecifier + Token Token + Token2 Token + Token3 Token + TypeName *TypeName +} + +// String implements fmt.Stringer. +func (n *AtomicTypeSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AtomicTypeSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() +} + +// AttributeSpecifier represents data reduced by production: +// +// AttributeSpecifier: +// "__attribute__" '(' '(' AttributeValueList ')' ')' +type AttributeSpecifier struct { + AttributeValueList *AttributeValueList + Token Token + Token2 Token + Token3 Token + Token4 Token + Token5 Token +} + +// String implements fmt.Stringer. +func (n *AttributeSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AttributeSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.AttributeValueList.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + return n.Token5.Position() +} + +// AttributeSpecifierList represents data reduced by productions: +// +// AttributeSpecifierList: +// AttributeSpecifier +// | AttributeSpecifierList AttributeSpecifier +type AttributeSpecifierList struct { + AttributeSpecifier *AttributeSpecifier + AttributeSpecifierList *AttributeSpecifierList +} + +// String implements fmt.Stringer. +func (n *AttributeSpecifierList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AttributeSpecifierList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.AttributeSpecifier.Position() +} + +// AttributeValueCase represents case numbers of production AttributeValue +type AttributeValueCase int + +// Values of type AttributeValueCase +const ( + AttributeValueIdent AttributeValueCase = iota + AttributeValueExpr +) + +// String implements fmt.Stringer +func (n AttributeValueCase) String() string { + switch n { + case AttributeValueIdent: + return "AttributeValueIdent" + case AttributeValueExpr: + return "AttributeValueExpr" + default: + return fmt.Sprintf("AttributeValueCase(%v)", int(n)) + } +} + +// AttributeValue represents data reduced by productions: +// +// AttributeValue: +// IDENTIFIER // Case AttributeValueIdent +// | IDENTIFIER '(' ExpressionList ')' // Case AttributeValueExpr +type AttributeValue struct { + lexicalScope Scope + Case AttributeValueCase `PrettyPrint:"stringer,zero"` + ExpressionList *ExpressionList + Token Token + Token2 Token + Token3 Token +} + +// String implements fmt.Stringer. +func (n *AttributeValue) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AttributeValue) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.Token.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.ExpressionList.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + default: + panic("internal error") + } +} + +// AttributeValueList represents data reduced by productions: +// +// AttributeValueList: +// AttributeValue +// | AttributeValueList ',' AttributeValue +type AttributeValueList struct { + AttributeValue *AttributeValue + AttributeValueList *AttributeValueList + Token Token +} + +// String implements fmt.Stringer. +func (n *AttributeValueList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *AttributeValueList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.AttributeValue.Position() +} + +// BlockItemCase represents case numbers of production BlockItem +type BlockItemCase int + +// Values of type BlockItemCase +const ( + BlockItemDecl BlockItemCase = iota + BlockItemStmt + BlockItemLabel + BlockItemFuncDef + BlockItemPragma +) + +// String implements fmt.Stringer +func (n BlockItemCase) String() string { + switch n { + case BlockItemDecl: + return "BlockItemDecl" + case BlockItemStmt: + return "BlockItemStmt" + case BlockItemLabel: + return "BlockItemLabel" + case BlockItemFuncDef: + return "BlockItemFuncDef" + case BlockItemPragma: + return "BlockItemPragma" + default: + return fmt.Sprintf("BlockItemCase(%v)", int(n)) + } +} + +// BlockItem represents data reduced by productions: +// +// BlockItem: +// Declaration // Case BlockItemDecl +// | Statement // Case BlockItemStmt +// | LabelDeclaration // Case BlockItemLabel +// | DeclarationSpecifiers Declarator CompoundStatement // Case BlockItemFuncDef +// | PragmaSTDC // Case BlockItemPragma +type BlockItem struct { + fn *FunctionDefinition // Case FuncDef + closure map[StringID]struct{} // Case FuncDef + Last bool + Case BlockItemCase `PrettyPrint:"stringer,zero"` + CompoundStatement *CompoundStatement + Declaration *Declaration + DeclarationSpecifiers *DeclarationSpecifiers + Declarator *Declarator + LabelDeclaration *LabelDeclaration + PragmaSTDC *PragmaSTDC + Statement *Statement +} + +// String implements fmt.Stringer. +func (n *BlockItem) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *BlockItem) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.Declaration.Position() + case 3: + if p := n.DeclarationSpecifiers.Position(); p.IsValid() { + return p + } + + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + return n.CompoundStatement.Position() + case 2: + return n.LabelDeclaration.Position() + case 4: + return n.PragmaSTDC.Position() + case 1: + return n.Statement.Position() + default: + panic("internal error") + } +} + +// BlockItemList represents data reduced by productions: +// +// BlockItemList: +// BlockItem +// | BlockItemList BlockItem +type BlockItemList struct { + BlockItem *BlockItem + BlockItemList *BlockItemList +} + +// String implements fmt.Stringer. +func (n *BlockItemList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *BlockItemList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.BlockItem.Position() +} + +// CastExpressionCase represents case numbers of production CastExpression +type CastExpressionCase int + +// Values of type CastExpressionCase +const ( + CastExpressionUnary CastExpressionCase = iota + CastExpressionCast +) + +// String implements fmt.Stringer +func (n CastExpressionCase) String() string { + switch n { + case CastExpressionUnary: + return "CastExpressionUnary" + case CastExpressionCast: + return "CastExpressionCast" + default: + return fmt.Sprintf("CastExpressionCase(%v)", int(n)) + } +} + +// CastExpression represents data reduced by productions: +// +// CastExpression: +// UnaryExpression // Case CastExpressionUnary +// | '(' TypeName ')' CastExpression // Case CastExpressionCast +type CastExpression struct { + Operand Operand + IsSideEffectsFree bool + Case CastExpressionCase `PrettyPrint:"stringer,zero"` + CastExpression *CastExpression + Token Token + Token2 Token + TypeName *TypeName + UnaryExpression *UnaryExpression +} + +// String implements fmt.Stringer. +func (n *CastExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *CastExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.CastExpression.Position() + case 0: + return n.UnaryExpression.Position() + default: + panic("internal error") + } +} + +// CompoundStatement represents data reduced by production: +// +// CompoundStatement: +// '{' BlockItemList '}' +type CompoundStatement struct { + Operand Operand + children []*CompoundStatement + declarations []*Declaration + isJumpTarget bool + labeledStmts []*LabeledStatement + parent *CompoundStatement + scope Scope + BlockItemList *BlockItemList + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *CompoundStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *CompoundStatement) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.BlockItemList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() +} + +// ConditionalExpressionCase represents case numbers of production ConditionalExpression +type ConditionalExpressionCase int + +// Values of type ConditionalExpressionCase +const ( + ConditionalExpressionLOr ConditionalExpressionCase = iota + ConditionalExpressionCond +) + +// String implements fmt.Stringer +func (n ConditionalExpressionCase) String() string { + switch n { + case ConditionalExpressionLOr: + return "ConditionalExpressionLOr" + case ConditionalExpressionCond: + return "ConditionalExpressionCond" + default: + return fmt.Sprintf("ConditionalExpressionCase(%v)", int(n)) + } +} + +// ConditionalExpression represents data reduced by productions: +// +// ConditionalExpression: +// LogicalOrExpression // Case ConditionalExpressionLOr +// | LogicalOrExpression '?' Expression ':' ConditionalExpression // Case ConditionalExpressionCond +type ConditionalExpression struct { + Operand Operand + IsSideEffectsFree bool + Case ConditionalExpressionCase `PrettyPrint:"stringer,zero"` + ConditionalExpression *ConditionalExpression + Expression *Expression + LogicalOrExpression *LogicalOrExpression + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *ConditionalExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ConditionalExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.LogicalOrExpression.Position() + case 1: + if p := n.LogicalOrExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.ConditionalExpression.Position() + default: + panic("internal error") + } +} + +// ConstantExpression represents data reduced by production: +// +// ConstantExpression: +// ConditionalExpression +type ConstantExpression struct { + Operand Operand + ConditionalExpression *ConditionalExpression +} + +// String implements fmt.Stringer. +func (n *ConstantExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ConstantExpression) Position() (r token.Position) { + if n == nil { + return r + } + + return n.ConditionalExpression.Position() +} + +// Declaration represents data reduced by production: +// +// Declaration: +// DeclarationSpecifiers InitDeclaratorList ';' +type Declaration struct { + DeclarationSpecifiers *DeclarationSpecifiers + InitDeclaratorList *InitDeclaratorList + Token Token +} + +// String implements fmt.Stringer. +func (n *Declaration) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Declaration) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.DeclarationSpecifiers.Position(); p.IsValid() { + return p + } + + if p := n.InitDeclaratorList.Position(); p.IsValid() { + return p + } + + return n.Token.Position() +} + +// DeclarationList represents data reduced by productions: +// +// DeclarationList: +// Declaration +// | DeclarationList Declaration +type DeclarationList struct { + Declaration *Declaration + DeclarationList *DeclarationList +} + +// String implements fmt.Stringer. +func (n *DeclarationList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *DeclarationList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Declaration.Position() +} + +// DeclarationSpecifiersCase represents case numbers of production DeclarationSpecifiers +type DeclarationSpecifiersCase int + +// Values of type DeclarationSpecifiersCase +const ( + DeclarationSpecifiersStorage DeclarationSpecifiersCase = iota + DeclarationSpecifiersTypeSpec + DeclarationSpecifiersTypeQual + DeclarationSpecifiersFunc + DeclarationSpecifiersAlignSpec + DeclarationSpecifiersAttribute +) + +// String implements fmt.Stringer +func (n DeclarationSpecifiersCase) String() string { + switch n { + case DeclarationSpecifiersStorage: + return "DeclarationSpecifiersStorage" + case DeclarationSpecifiersTypeSpec: + return "DeclarationSpecifiersTypeSpec" + case DeclarationSpecifiersTypeQual: + return "DeclarationSpecifiersTypeQual" + case DeclarationSpecifiersFunc: + return "DeclarationSpecifiersFunc" + case DeclarationSpecifiersAlignSpec: + return "DeclarationSpecifiersAlignSpec" + case DeclarationSpecifiersAttribute: + return "DeclarationSpecifiersAttribute" + default: + return fmt.Sprintf("DeclarationSpecifiersCase(%v)", int(n)) + } +} + +// DeclarationSpecifiers represents data reduced by productions: +// +// DeclarationSpecifiers: +// StorageClassSpecifier DeclarationSpecifiers // Case DeclarationSpecifiersStorage +// | TypeSpecifier DeclarationSpecifiers // Case DeclarationSpecifiersTypeSpec +// | TypeQualifier DeclarationSpecifiers // Case DeclarationSpecifiersTypeQual +// | FunctionSpecifier DeclarationSpecifiers // Case DeclarationSpecifiersFunc +// | AlignmentSpecifier DeclarationSpecifiers // Case DeclarationSpecifiersAlignSpec +// | AttributeSpecifier DeclarationSpecifiers // Case DeclarationSpecifiersAttribute +type DeclarationSpecifiers struct { + class storageClass + AlignmentSpecifier *AlignmentSpecifier + AttributeSpecifier *AttributeSpecifier + Case DeclarationSpecifiersCase `PrettyPrint:"stringer,zero"` + DeclarationSpecifiers *DeclarationSpecifiers + FunctionSpecifier *FunctionSpecifier + StorageClassSpecifier *StorageClassSpecifier + TypeQualifier *TypeQualifier + TypeSpecifier *TypeSpecifier +} + +// String implements fmt.Stringer. +func (n *DeclarationSpecifiers) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *DeclarationSpecifiers) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 4: + if p := n.AlignmentSpecifier.Position(); p.IsValid() { + return p + } + + return n.DeclarationSpecifiers.Position() + case 5: + if p := n.AttributeSpecifier.Position(); p.IsValid() { + return p + } + + return n.DeclarationSpecifiers.Position() + case 3: + if p := n.FunctionSpecifier.Position(); p.IsValid() { + return p + } + + return n.DeclarationSpecifiers.Position() + case 0: + if p := n.StorageClassSpecifier.Position(); p.IsValid() { + return p + } + + return n.DeclarationSpecifiers.Position() + case 2: + if p := n.TypeQualifier.Position(); p.IsValid() { + return p + } + + return n.DeclarationSpecifiers.Position() + case 1: + if p := n.TypeSpecifier.Position(); p.IsValid() { + return p + } + + return n.DeclarationSpecifiers.Position() + default: + panic("internal error") + } +} + +// Declarator represents data reduced by production: +// +// Declarator: +// Pointer DirectDeclarator AttributeSpecifierList +type Declarator struct { + Linkage Linkage + Read int + StorageClass StorageClass + Write int + funcDefinition *FunctionDefinition + lhs map[*Declarator]struct{} + td typeDescriptor + typ Type + AddressTaken bool + IsParameter bool + IsTypedefName bool + SubjectOfAsgnOp bool + SubjectOfIncDec bool + called bool + fnDef bool + hasInitializer bool + implicit bool + AttributeSpecifierList *AttributeSpecifierList + DirectDeclarator *DirectDeclarator + Pointer *Pointer +} + +// String implements fmt.Stringer. +func (n *Declarator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Declarator) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Pointer.Position(); p.IsValid() { + return p + } + + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + return n.AttributeSpecifierList.Position() +} + +// Designation represents data reduced by production: +// +// Designation: +// DesignatorList '=' +type Designation struct { + DesignatorList *DesignatorList + Token Token +} + +// String implements fmt.Stringer. +func (n *Designation) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Designation) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.DesignatorList.Position(); p.IsValid() { + return p + } + + return n.Token.Position() +} + +// DesignatorCase represents case numbers of production Designator +type DesignatorCase int + +// Values of type DesignatorCase +const ( + DesignatorIndex DesignatorCase = iota + DesignatorField + DesignatorField2 +) + +// String implements fmt.Stringer +func (n DesignatorCase) String() string { + switch n { + case DesignatorIndex: + return "DesignatorIndex" + case DesignatorField: + return "DesignatorField" + case DesignatorField2: + return "DesignatorField2" + default: + return fmt.Sprintf("DesignatorCase(%v)", int(n)) + } +} + +// Designator represents data reduced by productions: +// +// Designator: +// '[' ConstantExpression ']' // Case DesignatorIndex +// | '.' IDENTIFIER // Case DesignatorField +// | IDENTIFIER ':' // Case DesignatorField2 +type Designator struct { + lexicalScope Scope + Case DesignatorCase `PrettyPrint:"stringer,zero"` + ConstantExpression *ConstantExpression + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *Designator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Designator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ConstantExpression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 1, 2: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + default: + panic("internal error") + } +} + +// DesignatorList represents data reduced by productions: +// +// DesignatorList: +// Designator +// | DesignatorList Designator +type DesignatorList struct { + Designator *Designator + DesignatorList *DesignatorList +} + +// String implements fmt.Stringer. +func (n *DesignatorList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *DesignatorList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Designator.Position() +} + +// DirectAbstractDeclaratorCase represents case numbers of production DirectAbstractDeclarator +type DirectAbstractDeclaratorCase int + +// Values of type DirectAbstractDeclaratorCase +const ( + DirectAbstractDeclaratorDecl DirectAbstractDeclaratorCase = iota + DirectAbstractDeclaratorArr + DirectAbstractDeclaratorStaticArr + DirectAbstractDeclaratorArrStatic + DirectAbstractDeclaratorArrStar + DirectAbstractDeclaratorFunc +) + +// String implements fmt.Stringer +func (n DirectAbstractDeclaratorCase) String() string { + switch n { + case DirectAbstractDeclaratorDecl: + return "DirectAbstractDeclaratorDecl" + case DirectAbstractDeclaratorArr: + return "DirectAbstractDeclaratorArr" + case DirectAbstractDeclaratorStaticArr: + return "DirectAbstractDeclaratorStaticArr" + case DirectAbstractDeclaratorArrStatic: + return "DirectAbstractDeclaratorArrStatic" + case DirectAbstractDeclaratorArrStar: + return "DirectAbstractDeclaratorArrStar" + case DirectAbstractDeclaratorFunc: + return "DirectAbstractDeclaratorFunc" + default: + return fmt.Sprintf("DirectAbstractDeclaratorCase(%v)", int(n)) + } +} + +// DirectAbstractDeclarator represents data reduced by productions: +// +// DirectAbstractDeclarator: +// '(' AbstractDeclarator ')' // Case DirectAbstractDeclaratorDecl +// | DirectAbstractDeclarator '[' TypeQualifiers AssignmentExpression ']' // Case DirectAbstractDeclaratorArr +// | DirectAbstractDeclarator '[' "static" TypeQualifiers AssignmentExpression ']' // Case DirectAbstractDeclaratorStaticArr +// | DirectAbstractDeclarator '[' TypeQualifiers "static" AssignmentExpression ']' // Case DirectAbstractDeclaratorArrStatic +// | DirectAbstractDeclarator '[' '*' ']' // Case DirectAbstractDeclaratorArrStar +// | DirectAbstractDeclarator '(' ParameterTypeList ')' // Case DirectAbstractDeclaratorFunc +type DirectAbstractDeclarator struct { + paramScope Scope + typeQualifiers *typeBase + AbstractDeclarator *AbstractDeclarator + AssignmentExpression *AssignmentExpression + Case DirectAbstractDeclaratorCase `PrettyPrint:"stringer,zero"` + DirectAbstractDeclarator *DirectAbstractDeclarator + ParameterTypeList *ParameterTypeList + Token Token + Token2 Token + Token3 Token + TypeQualifiers *TypeQualifiers +} + +// String implements fmt.Stringer. +func (n *DirectAbstractDeclarator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *DirectAbstractDeclarator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 5: + if p := n.DirectAbstractDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ParameterTypeList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 4: + if p := n.DirectAbstractDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 2: + if p := n.DirectAbstractDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 1: + if p := n.DirectAbstractDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 3: + if p := n.DirectAbstractDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.AbstractDeclarator.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + default: + panic("internal error") + } +} + +// DirectDeclaratorCase represents case numbers of production DirectDeclarator +type DirectDeclaratorCase int + +// Values of type DirectDeclaratorCase +const ( + DirectDeclaratorIdent DirectDeclaratorCase = iota + DirectDeclaratorDecl + DirectDeclaratorArr + DirectDeclaratorStaticArr + DirectDeclaratorArrStatic + DirectDeclaratorStar + DirectDeclaratorFuncParam + DirectDeclaratorFuncIdent +) + +// String implements fmt.Stringer +func (n DirectDeclaratorCase) String() string { + switch n { + case DirectDeclaratorIdent: + return "DirectDeclaratorIdent" + case DirectDeclaratorDecl: + return "DirectDeclaratorDecl" + case DirectDeclaratorArr: + return "DirectDeclaratorArr" + case DirectDeclaratorStaticArr: + return "DirectDeclaratorStaticArr" + case DirectDeclaratorArrStatic: + return "DirectDeclaratorArrStatic" + case DirectDeclaratorStar: + return "DirectDeclaratorStar" + case DirectDeclaratorFuncParam: + return "DirectDeclaratorFuncParam" + case DirectDeclaratorFuncIdent: + return "DirectDeclaratorFuncIdent" + default: + return fmt.Sprintf("DirectDeclaratorCase(%v)", int(n)) + } +} + +// DirectDeclarator represents data reduced by productions: +// +// DirectDeclarator: +// IDENTIFIER Asm // Case DirectDeclaratorIdent +// | '(' AttributeSpecifierList Declarator ')' // Case DirectDeclaratorDecl +// | DirectDeclarator '[' TypeQualifiers AssignmentExpression ']' // Case DirectDeclaratorArr +// | DirectDeclarator '[' "static" TypeQualifiers AssignmentExpression ']' // Case DirectDeclaratorStaticArr +// | DirectDeclarator '[' TypeQualifiers "static" AssignmentExpression ']' // Case DirectDeclaratorArrStatic +// | DirectDeclarator '[' TypeQualifiers '*' ']' // Case DirectDeclaratorStar +// | DirectDeclarator '(' ParameterTypeList ')' // Case DirectDeclaratorFuncParam +// | DirectDeclarator '(' IdentifierList ')' // Case DirectDeclaratorFuncIdent +type DirectDeclarator struct { + lexicalScope Scope + paramScope Scope + typeQualifiers *typeBase + idListNoDeclList bool + Asm *Asm + AssignmentExpression *AssignmentExpression + AttributeSpecifierList *AttributeSpecifierList + Case DirectDeclaratorCase `PrettyPrint:"stringer,zero"` + Declarator *Declarator + DirectDeclarator *DirectDeclarator + IdentifierList *IdentifierList + ParameterTypeList *ParameterTypeList + Token Token + Token2 Token + Token3 Token + TypeQualifiers *TypeQualifiers +} + +// String implements fmt.Stringer. +func (n *DirectDeclarator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *DirectDeclarator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 7: + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.IdentifierList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 6: + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ParameterTypeList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 3: + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 2: + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 4: + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 5: + if p := n.DirectDeclarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Asm.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + default: + panic("internal error") + } +} + +// EnumSpecifierCase represents case numbers of production EnumSpecifier +type EnumSpecifierCase int + +// Values of type EnumSpecifierCase +const ( + EnumSpecifierDef EnumSpecifierCase = iota + EnumSpecifierTag +) + +// String implements fmt.Stringer +func (n EnumSpecifierCase) String() string { + switch n { + case EnumSpecifierDef: + return "EnumSpecifierDef" + case EnumSpecifierTag: + return "EnumSpecifierTag" + default: + return fmt.Sprintf("EnumSpecifierCase(%v)", int(n)) + } +} + +// EnumSpecifier represents data reduced by productions: +// +// EnumSpecifier: +// "enum" AttributeSpecifierList IDENTIFIER '{' EnumeratorList ',' '}' // Case EnumSpecifierDef +// | "enum" AttributeSpecifierList IDENTIFIER // Case EnumSpecifierTag +type EnumSpecifier struct { + lexicalScope Scope + typ Type + min Value + max Value + AttributeSpecifierList *AttributeSpecifierList + Case EnumSpecifierCase `PrettyPrint:"stringer,zero"` + EnumeratorList *EnumeratorList + Token Token + Token2 Token + Token3 Token + Token4 Token + Token5 Token +} + +// String implements fmt.Stringer. +func (n *EnumSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *EnumSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.EnumeratorList.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + return n.Token5.Position() + default: + panic("internal error") + } +} + +// EnumeratorCase represents case numbers of production Enumerator +type EnumeratorCase int + +// Values of type EnumeratorCase +const ( + EnumeratorIdent EnumeratorCase = iota + EnumeratorExpr +) + +// String implements fmt.Stringer +func (n EnumeratorCase) String() string { + switch n { + case EnumeratorIdent: + return "EnumeratorIdent" + case EnumeratorExpr: + return "EnumeratorExpr" + default: + return fmt.Sprintf("EnumeratorCase(%v)", int(n)) + } +} + +// Enumerator represents data reduced by productions: +// +// Enumerator: +// IDENTIFIER AttributeSpecifierList // Case EnumeratorIdent +// | IDENTIFIER AttributeSpecifierList '=' ConstantExpression // Case EnumeratorExpr +type Enumerator struct { + lexicalScope Scope + Operand Operand + AttributeSpecifierList *AttributeSpecifierList + Case EnumeratorCase `PrettyPrint:"stringer,zero"` + ConstantExpression *ConstantExpression + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *Enumerator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Enumerator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.AttributeSpecifierList.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.ConstantExpression.Position() + default: + panic("internal error") + } +} + +// EnumeratorList represents data reduced by productions: +// +// EnumeratorList: +// Enumerator +// | EnumeratorList ',' Enumerator +type EnumeratorList struct { + Enumerator *Enumerator + EnumeratorList *EnumeratorList + Token Token +} + +// String implements fmt.Stringer. +func (n *EnumeratorList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *EnumeratorList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Enumerator.Position() +} + +// EqualityExpressionCase represents case numbers of production EqualityExpression +type EqualityExpressionCase int + +// Values of type EqualityExpressionCase +const ( + EqualityExpressionRel EqualityExpressionCase = iota + EqualityExpressionEq + EqualityExpressionNeq +) + +// String implements fmt.Stringer +func (n EqualityExpressionCase) String() string { + switch n { + case EqualityExpressionRel: + return "EqualityExpressionRel" + case EqualityExpressionEq: + return "EqualityExpressionEq" + case EqualityExpressionNeq: + return "EqualityExpressionNeq" + default: + return fmt.Sprintf("EqualityExpressionCase(%v)", int(n)) + } +} + +// EqualityExpression represents data reduced by productions: +// +// EqualityExpression: +// RelationalExpression // Case EqualityExpressionRel +// | EqualityExpression "==" RelationalExpression // Case EqualityExpressionEq +// | EqualityExpression "!=" RelationalExpression // Case EqualityExpressionNeq +type EqualityExpression struct { + Operand Operand + promote Type + IsSideEffectsFree bool + Case EqualityExpressionCase `PrettyPrint:"stringer,zero"` + EqualityExpression *EqualityExpression + RelationalExpression *RelationalExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *EqualityExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *EqualityExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1, 2: + if p := n.EqualityExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.RelationalExpression.Position() + case 0: + return n.RelationalExpression.Position() + default: + panic("internal error") + } +} + +// ExclusiveOrExpressionCase represents case numbers of production ExclusiveOrExpression +type ExclusiveOrExpressionCase int + +// Values of type ExclusiveOrExpressionCase +const ( + ExclusiveOrExpressionAnd ExclusiveOrExpressionCase = iota + ExclusiveOrExpressionXor +) + +// String implements fmt.Stringer +func (n ExclusiveOrExpressionCase) String() string { + switch n { + case ExclusiveOrExpressionAnd: + return "ExclusiveOrExpressionAnd" + case ExclusiveOrExpressionXor: + return "ExclusiveOrExpressionXor" + default: + return fmt.Sprintf("ExclusiveOrExpressionCase(%v)", int(n)) + } +} + +// ExclusiveOrExpression represents data reduced by productions: +// +// ExclusiveOrExpression: +// AndExpression // Case ExclusiveOrExpressionAnd +// | ExclusiveOrExpression '^' AndExpression // Case ExclusiveOrExpressionXor +type ExclusiveOrExpression struct { + Operand Operand + promote Type + IsSideEffectsFree bool + AndExpression *AndExpression + Case ExclusiveOrExpressionCase `PrettyPrint:"stringer,zero"` + ExclusiveOrExpression *ExclusiveOrExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *ExclusiveOrExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ExclusiveOrExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.AndExpression.Position() + case 1: + if p := n.ExclusiveOrExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.AndExpression.Position() + default: + panic("internal error") + } +} + +// ExpressionCase represents case numbers of production Expression +type ExpressionCase int + +// Values of type ExpressionCase +const ( + ExpressionAssign ExpressionCase = iota + ExpressionComma +) + +// String implements fmt.Stringer +func (n ExpressionCase) String() string { + switch n { + case ExpressionAssign: + return "ExpressionAssign" + case ExpressionComma: + return "ExpressionComma" + default: + return fmt.Sprintf("ExpressionCase(%v)", int(n)) + } +} + +// Expression represents data reduced by productions: +// +// Expression: +// AssignmentExpression // Case ExpressionAssign +// | Expression ',' AssignmentExpression // Case ExpressionComma +type Expression struct { + Operand Operand + IsSideEffectsFree bool + AssignmentExpression *AssignmentExpression + Case ExpressionCase `PrettyPrint:"stringer,zero"` + Expression *Expression + Token Token +} + +// String implements fmt.Stringer. +func (n *Expression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Expression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.AssignmentExpression.Position() + case 1: + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.AssignmentExpression.Position() + default: + panic("internal error") + } +} + +// ExpressionList represents data reduced by productions: +// +// ExpressionList: +// AssignmentExpression +// | ExpressionList ',' AssignmentExpression +type ExpressionList struct { + AssignmentExpression *AssignmentExpression + ExpressionList *ExpressionList + Token Token +} + +// String implements fmt.Stringer. +func (n *ExpressionList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ExpressionList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.AssignmentExpression.Position() +} + +// ExpressionStatement represents data reduced by production: +// +// ExpressionStatement: +// Expression AttributeSpecifierList ';' +type ExpressionStatement struct { + AttributeSpecifierList *AttributeSpecifierList + Expression *Expression + Token Token +} + +// String implements fmt.Stringer. +func (n *ExpressionStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ExpressionStatement) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + return n.Token.Position() +} + +// ExternalDeclarationCase represents case numbers of production ExternalDeclaration +type ExternalDeclarationCase int + +// Values of type ExternalDeclarationCase +const ( + ExternalDeclarationFuncDef ExternalDeclarationCase = iota + ExternalDeclarationDecl + ExternalDeclarationAsm + ExternalDeclarationAsmStmt + ExternalDeclarationEmpty + ExternalDeclarationPragma +) + +// String implements fmt.Stringer +func (n ExternalDeclarationCase) String() string { + switch n { + case ExternalDeclarationFuncDef: + return "ExternalDeclarationFuncDef" + case ExternalDeclarationDecl: + return "ExternalDeclarationDecl" + case ExternalDeclarationAsm: + return "ExternalDeclarationAsm" + case ExternalDeclarationAsmStmt: + return "ExternalDeclarationAsmStmt" + case ExternalDeclarationEmpty: + return "ExternalDeclarationEmpty" + case ExternalDeclarationPragma: + return "ExternalDeclarationPragma" + default: + return fmt.Sprintf("ExternalDeclarationCase(%v)", int(n)) + } +} + +// ExternalDeclaration represents data reduced by productions: +// +// ExternalDeclaration: +// FunctionDefinition // Case ExternalDeclarationFuncDef +// | Declaration // Case ExternalDeclarationDecl +// | AsmFunctionDefinition // Case ExternalDeclarationAsm +// | AsmStatement // Case ExternalDeclarationAsmStmt +// | ';' // Case ExternalDeclarationEmpty +// | PragmaSTDC // Case ExternalDeclarationPragma +type ExternalDeclaration struct { + AsmFunctionDefinition *AsmFunctionDefinition + AsmStatement *AsmStatement + Case ExternalDeclarationCase `PrettyPrint:"stringer,zero"` + Declaration *Declaration + FunctionDefinition *FunctionDefinition + PragmaSTDC *PragmaSTDC + Token Token +} + +// String implements fmt.Stringer. +func (n *ExternalDeclaration) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ExternalDeclaration) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 2: + return n.AsmFunctionDefinition.Position() + case 3: + return n.AsmStatement.Position() + case 1: + return n.Declaration.Position() + case 0: + return n.FunctionDefinition.Position() + case 5: + return n.PragmaSTDC.Position() + case 4: + return n.Token.Position() + default: + panic("internal error") + } +} + +// FunctionDefinition represents data reduced by production: +// +// FunctionDefinition: +// DeclarationSpecifiers Declarator DeclarationList CompoundStatement +type FunctionDefinition struct { + CallSiteComplexExpr []*AssignmentExpression + CompositeLiterals []*PostfixExpression + ComputedGotos map[StringID]*UnaryExpression + Gotos map[StringID]*JumpStatement + InitDeclarators []*InitDeclarator + Labels map[StringID]*LabeledStatement + ReturnComplexExpr []*Expression + VLAs []*Declarator + compoundStatements []*CompoundStatement + checked bool + CompoundStatement *CompoundStatement + DeclarationList *DeclarationList + DeclarationSpecifiers *DeclarationSpecifiers + Declarator *Declarator +} + +// String implements fmt.Stringer. +func (n *FunctionDefinition) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *FunctionDefinition) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.DeclarationSpecifiers.Position(); p.IsValid() { + return p + } + + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + if p := n.DeclarationList.Position(); p.IsValid() { + return p + } + + return n.CompoundStatement.Position() +} + +// FunctionSpecifierCase represents case numbers of production FunctionSpecifier +type FunctionSpecifierCase int + +// Values of type FunctionSpecifierCase +const ( + FunctionSpecifierInline FunctionSpecifierCase = iota + FunctionSpecifierNoreturn +) + +// String implements fmt.Stringer +func (n FunctionSpecifierCase) String() string { + switch n { + case FunctionSpecifierInline: + return "FunctionSpecifierInline" + case FunctionSpecifierNoreturn: + return "FunctionSpecifierNoreturn" + default: + return fmt.Sprintf("FunctionSpecifierCase(%v)", int(n)) + } +} + +// FunctionSpecifier represents data reduced by productions: +// +// FunctionSpecifier: +// "inline" // Case FunctionSpecifierInline +// | "_Noreturn" // Case FunctionSpecifierNoreturn +type FunctionSpecifier struct { + Case FunctionSpecifierCase `PrettyPrint:"stringer,zero"` + Token Token +} + +// String implements fmt.Stringer. +func (n *FunctionSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *FunctionSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Token.Position() +} + +// IdentifierList represents data reduced by productions: +// +// IdentifierList: +// IDENTIFIER +// | IdentifierList ',' IDENTIFIER +type IdentifierList struct { + lexicalScope Scope + IdentifierList *IdentifierList + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *IdentifierList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *IdentifierList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Token.Position() +} + +// InclusiveOrExpressionCase represents case numbers of production InclusiveOrExpression +type InclusiveOrExpressionCase int + +// Values of type InclusiveOrExpressionCase +const ( + InclusiveOrExpressionXor InclusiveOrExpressionCase = iota + InclusiveOrExpressionOr +) + +// String implements fmt.Stringer +func (n InclusiveOrExpressionCase) String() string { + switch n { + case InclusiveOrExpressionXor: + return "InclusiveOrExpressionXor" + case InclusiveOrExpressionOr: + return "InclusiveOrExpressionOr" + default: + return fmt.Sprintf("InclusiveOrExpressionCase(%v)", int(n)) + } +} + +// InclusiveOrExpression represents data reduced by productions: +// +// InclusiveOrExpression: +// ExclusiveOrExpression // Case InclusiveOrExpressionXor +// | InclusiveOrExpression '|' ExclusiveOrExpression // Case InclusiveOrExpressionOr +type InclusiveOrExpression struct { + Operand Operand + promote Type + IsSideEffectsFree bool + Case InclusiveOrExpressionCase `PrettyPrint:"stringer,zero"` + ExclusiveOrExpression *ExclusiveOrExpression + InclusiveOrExpression *InclusiveOrExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *InclusiveOrExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *InclusiveOrExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.ExclusiveOrExpression.Position() + case 1: + if p := n.InclusiveOrExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.ExclusiveOrExpression.Position() + default: + panic("internal error") + } +} + +// InitDeclaratorCase represents case numbers of production InitDeclarator +type InitDeclaratorCase int + +// Values of type InitDeclaratorCase +const ( + InitDeclaratorDecl InitDeclaratorCase = iota + InitDeclaratorInit +) + +// String implements fmt.Stringer +func (n InitDeclaratorCase) String() string { + switch n { + case InitDeclaratorDecl: + return "InitDeclaratorDecl" + case InitDeclaratorInit: + return "InitDeclaratorInit" + default: + return fmt.Sprintf("InitDeclaratorCase(%v)", int(n)) + } +} + +// InitDeclarator represents data reduced by productions: +// +// InitDeclarator: +// Declarator AttributeSpecifierList // Case InitDeclaratorDecl +// | Declarator AttributeSpecifierList '=' Initializer // Case InitDeclaratorInit +type InitDeclarator struct { + initializer *InitializerValue + AttributeSpecifierList *AttributeSpecifierList + Case InitDeclaratorCase `PrettyPrint:"stringer,zero"` + Declarator *Declarator + Initializer *Initializer + Token Token +} + +// String implements fmt.Stringer. +func (n *InitDeclarator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *InitDeclarator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + return n.AttributeSpecifierList.Position() + case 1: + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Initializer.Position() + default: + panic("internal error") + } +} + +// InitDeclaratorList represents data reduced by productions: +// +// InitDeclaratorList: +// InitDeclarator +// | InitDeclaratorList ',' AttributeSpecifierList InitDeclarator +type InitDeclaratorList struct { + AttributeSpecifierList *AttributeSpecifierList + InitDeclarator *InitDeclarator + InitDeclaratorList *InitDeclaratorList + Token Token +} + +// String implements fmt.Stringer. +func (n *InitDeclaratorList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *InitDeclaratorList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.InitDeclarator.Position() +} + +// InitializerCase represents case numbers of production Initializer +type InitializerCase int + +// Values of type InitializerCase +const ( + InitializerExpr InitializerCase = iota + InitializerInitList +) + +// String implements fmt.Stringer +func (n InitializerCase) String() string { + switch n { + case InitializerExpr: + return "InitializerExpr" + case InitializerInitList: + return "InitializerInitList" + default: + return fmt.Sprintf("InitializerCase(%v)", int(n)) + } +} + +// Initializer represents data reduced by productions: +// +// Initializer: +// AssignmentExpression // Case InitializerExpr +// | '{' InitializerList ',' '}' // Case InitializerInitList +type Initializer struct { + Field Field // Where aplicable + Offset uintptr // Case Expr + field0 Field + list []*Initializer + parent *Initializer + trailingComma *Token + typ Type + isConst bool + isZero bool + AssignmentExpression *AssignmentExpression + Case InitializerCase `PrettyPrint:"stringer,zero"` + InitializerList *InitializerList + Token Token + Token2 Token + Token3 Token +} + +// String implements fmt.Stringer. +func (n *Initializer) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Initializer) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.AssignmentExpression.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.InitializerList.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + default: + panic("internal error") + } +} + +// InitializerList represents data reduced by productions: +// +// InitializerList: +// Designation Initializer +// | InitializerList ',' Designation Initializer +type InitializerList struct { + list []*Initializer + isConst bool + isZero bool + Designation *Designation + Initializer *Initializer + InitializerList *InitializerList + Token Token +} + +// String implements fmt.Stringer. +func (n *InitializerList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *InitializerList) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Designation.Position(); p.IsValid() { + return p + } + + return n.Initializer.Position() +} + +// IterationStatementCase represents case numbers of production IterationStatement +type IterationStatementCase int + +// Values of type IterationStatementCase +const ( + IterationStatementWhile IterationStatementCase = iota + IterationStatementDo + IterationStatementFor + IterationStatementForDecl +) + +// String implements fmt.Stringer +func (n IterationStatementCase) String() string { + switch n { + case IterationStatementWhile: + return "IterationStatementWhile" + case IterationStatementDo: + return "IterationStatementDo" + case IterationStatementFor: + return "IterationStatementFor" + case IterationStatementForDecl: + return "IterationStatementForDecl" + default: + return fmt.Sprintf("IterationStatementCase(%v)", int(n)) + } +} + +// IterationStatement represents data reduced by productions: +// +// IterationStatement: +// "while" '(' Expression ')' Statement // Case IterationStatementWhile +// | "do" Statement "while" '(' Expression ')' ';' // Case IterationStatementDo +// | "for" '(' Expression ';' Expression ';' Expression ')' Statement // Case IterationStatementFor +// | "for" '(' Declaration Expression ';' Expression ')' Statement // Case IterationStatementForDecl +type IterationStatement struct { + Case IterationStatementCase `PrettyPrint:"stringer,zero"` + Declaration *Declaration + Expression *Expression + Expression2 *Expression + Expression3 *Expression + Statement *Statement + Token Token + Token2 Token + Token3 Token + Token4 Token + Token5 Token +} + +// String implements fmt.Stringer. +func (n *IterationStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *IterationStatement) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Statement.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + return n.Token5.Position() + case 3: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Declaration.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.Expression2.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + case 2: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.Expression2.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + if p := n.Expression3.Position(); p.IsValid() { + return p + } + + if p := n.Token5.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + default: + panic("internal error") + } +} + +// JumpStatementCase represents case numbers of production JumpStatement +type JumpStatementCase int + +// Values of type JumpStatementCase +const ( + JumpStatementGoto JumpStatementCase = iota + JumpStatementGotoExpr + JumpStatementContinue + JumpStatementBreak + JumpStatementReturn +) + +// String implements fmt.Stringer +func (n JumpStatementCase) String() string { + switch n { + case JumpStatementGoto: + return "JumpStatementGoto" + case JumpStatementGotoExpr: + return "JumpStatementGotoExpr" + case JumpStatementContinue: + return "JumpStatementContinue" + case JumpStatementBreak: + return "JumpStatementBreak" + case JumpStatementReturn: + return "JumpStatementReturn" + default: + return fmt.Sprintf("JumpStatementCase(%v)", int(n)) + } +} + +// JumpStatement represents data reduced by productions: +// +// JumpStatement: +// "goto" IDENTIFIER ';' // Case JumpStatementGoto +// | "goto" '*' Expression ';' // Case JumpStatementGotoExpr +// | "continue" ';' // Case JumpStatementContinue +// | "break" ';' // Case JumpStatementBreak +// | "return" Expression ';' // Case JumpStatementReturn +type JumpStatement struct { + context Node + lexicalScope Scope + Case JumpStatementCase `PrettyPrint:"stringer,zero"` + Expression *Expression + Token Token + Token2 Token + Token3 Token +} + +// String implements fmt.Stringer. +func (n *JumpStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *JumpStatement) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 4: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 2, 3: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + default: + panic("internal error") + } +} + +// LabelDeclaration represents data reduced by production: +// +// LabelDeclaration: +// "__label__" IdentifierList ';' +type LabelDeclaration struct { + IdentifierList *IdentifierList + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *LabelDeclaration) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *LabelDeclaration) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.IdentifierList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() +} + +// LabeledStatementCase represents case numbers of production LabeledStatement +type LabeledStatementCase int + +// Values of type LabeledStatementCase +const ( + LabeledStatementLabel LabeledStatementCase = iota + LabeledStatementCaseLabel + LabeledStatementRange + LabeledStatementDefault +) + +// String implements fmt.Stringer +func (n LabeledStatementCase) String() string { + switch n { + case LabeledStatementLabel: + return "LabeledStatementLabel" + case LabeledStatementCaseLabel: + return "LabeledStatementCaseLabel" + case LabeledStatementRange: + return "LabeledStatementRange" + case LabeledStatementDefault: + return "LabeledStatementDefault" + default: + return fmt.Sprintf("LabeledStatementCase(%v)", int(n)) + } +} + +// LabeledStatement represents data reduced by productions: +// +// LabeledStatement: +// IDENTIFIER ':' AttributeSpecifierList Statement // Case LabeledStatementLabel +// | "case" ConstantExpression ':' Statement // Case LabeledStatementCaseLabel +// | "case" ConstantExpression "..." ConstantExpression ':' Statement // Case LabeledStatementRange +// | "default" ':' Statement // Case LabeledStatementDefault +type LabeledStatement struct { + block *CompoundStatement + lexicalScope Scope + AttributeSpecifierList *AttributeSpecifierList + Case LabeledStatementCase `PrettyPrint:"stringer,zero"` + ConstantExpression *ConstantExpression + ConstantExpression2 *ConstantExpression + Statement *Statement + Token Token + Token2 Token + Token3 Token +} + +// String implements fmt.Stringer. +func (n *LabeledStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *LabeledStatement) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 2: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ConstantExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.ConstantExpression2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ConstantExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + case 0: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + case 3: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + default: + panic("internal error") + } +} + +// LogicalAndExpressionCase represents case numbers of production LogicalAndExpression +type LogicalAndExpressionCase int + +// Values of type LogicalAndExpressionCase +const ( + LogicalAndExpressionOr LogicalAndExpressionCase = iota + LogicalAndExpressionLAnd +) + +// String implements fmt.Stringer +func (n LogicalAndExpressionCase) String() string { + switch n { + case LogicalAndExpressionOr: + return "LogicalAndExpressionOr" + case LogicalAndExpressionLAnd: + return "LogicalAndExpressionLAnd" + default: + return fmt.Sprintf("LogicalAndExpressionCase(%v)", int(n)) + } +} + +// LogicalAndExpression represents data reduced by productions: +// +// LogicalAndExpression: +// InclusiveOrExpression // Case LogicalAndExpressionOr +// | LogicalAndExpression "&&" InclusiveOrExpression // Case LogicalAndExpressionLAnd +type LogicalAndExpression struct { + Operand Operand + IsSideEffectsFree bool + Case LogicalAndExpressionCase `PrettyPrint:"stringer,zero"` + InclusiveOrExpression *InclusiveOrExpression + LogicalAndExpression *LogicalAndExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *LogicalAndExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *LogicalAndExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.InclusiveOrExpression.Position() + case 1: + if p := n.LogicalAndExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.InclusiveOrExpression.Position() + default: + panic("internal error") + } +} + +// LogicalOrExpressionCase represents case numbers of production LogicalOrExpression +type LogicalOrExpressionCase int + +// Values of type LogicalOrExpressionCase +const ( + LogicalOrExpressionLAnd LogicalOrExpressionCase = iota + LogicalOrExpressionLOr +) + +// String implements fmt.Stringer +func (n LogicalOrExpressionCase) String() string { + switch n { + case LogicalOrExpressionLAnd: + return "LogicalOrExpressionLAnd" + case LogicalOrExpressionLOr: + return "LogicalOrExpressionLOr" + default: + return fmt.Sprintf("LogicalOrExpressionCase(%v)", int(n)) + } +} + +// LogicalOrExpression represents data reduced by productions: +// +// LogicalOrExpression: +// LogicalAndExpression // Case LogicalOrExpressionLAnd +// | LogicalOrExpression "||" LogicalAndExpression // Case LogicalOrExpressionLOr +type LogicalOrExpression struct { + Operand Operand + IsSideEffectsFree bool + Case LogicalOrExpressionCase `PrettyPrint:"stringer,zero"` + LogicalAndExpression *LogicalAndExpression + LogicalOrExpression *LogicalOrExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *LogicalOrExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *LogicalOrExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.LogicalAndExpression.Position() + case 1: + if p := n.LogicalOrExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.LogicalAndExpression.Position() + default: + panic("internal error") + } +} + +// MultiplicativeExpressionCase represents case numbers of production MultiplicativeExpression +type MultiplicativeExpressionCase int + +// Values of type MultiplicativeExpressionCase +const ( + MultiplicativeExpressionCast MultiplicativeExpressionCase = iota + MultiplicativeExpressionMul + MultiplicativeExpressionDiv + MultiplicativeExpressionMod +) + +// String implements fmt.Stringer +func (n MultiplicativeExpressionCase) String() string { + switch n { + case MultiplicativeExpressionCast: + return "MultiplicativeExpressionCast" + case MultiplicativeExpressionMul: + return "MultiplicativeExpressionMul" + case MultiplicativeExpressionDiv: + return "MultiplicativeExpressionDiv" + case MultiplicativeExpressionMod: + return "MultiplicativeExpressionMod" + default: + return fmt.Sprintf("MultiplicativeExpressionCase(%v)", int(n)) + } +} + +// MultiplicativeExpression represents data reduced by productions: +// +// MultiplicativeExpression: +// CastExpression // Case MultiplicativeExpressionCast +// | MultiplicativeExpression '*' CastExpression // Case MultiplicativeExpressionMul +// | MultiplicativeExpression '/' CastExpression // Case MultiplicativeExpressionDiv +// | MultiplicativeExpression '%' CastExpression // Case MultiplicativeExpressionMod +type MultiplicativeExpression struct { + Operand Operand + promote Type + IsSideEffectsFree bool + Case MultiplicativeExpressionCase `PrettyPrint:"stringer,zero"` + CastExpression *CastExpression + MultiplicativeExpression *MultiplicativeExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *MultiplicativeExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *MultiplicativeExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.CastExpression.Position() + case 1, 2, 3: + if p := n.MultiplicativeExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.CastExpression.Position() + default: + panic("internal error") + } +} + +// ParameterDeclarationCase represents case numbers of production ParameterDeclaration +type ParameterDeclarationCase int + +// Values of type ParameterDeclarationCase +const ( + ParameterDeclarationDecl ParameterDeclarationCase = iota + ParameterDeclarationAbstract +) + +// String implements fmt.Stringer +func (n ParameterDeclarationCase) String() string { + switch n { + case ParameterDeclarationDecl: + return "ParameterDeclarationDecl" + case ParameterDeclarationAbstract: + return "ParameterDeclarationAbstract" + default: + return fmt.Sprintf("ParameterDeclarationCase(%v)", int(n)) + } +} + +// ParameterDeclaration represents data reduced by productions: +// +// ParameterDeclaration: +// DeclarationSpecifiers Declarator AttributeSpecifierList // Case ParameterDeclarationDecl +// | DeclarationSpecifiers AbstractDeclarator // Case ParameterDeclarationAbstract +type ParameterDeclaration struct { + typ Type + AbstractDeclarator *AbstractDeclarator + AttributeSpecifierList *AttributeSpecifierList + Case ParameterDeclarationCase `PrettyPrint:"stringer,zero"` + DeclarationSpecifiers *DeclarationSpecifiers + Declarator *Declarator +} + +// String implements fmt.Stringer. +func (n *ParameterDeclaration) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ParameterDeclaration) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.DeclarationSpecifiers.Position(); p.IsValid() { + return p + } + + return n.AbstractDeclarator.Position() + case 0: + if p := n.DeclarationSpecifiers.Position(); p.IsValid() { + return p + } + + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + return n.AttributeSpecifierList.Position() + default: + panic("internal error") + } +} + +// ParameterList represents data reduced by productions: +// +// ParameterList: +// ParameterDeclaration +// | ParameterList ',' ParameterDeclaration +type ParameterList struct { + ParameterDeclaration *ParameterDeclaration + ParameterList *ParameterList + Token Token +} + +// String implements fmt.Stringer. +func (n *ParameterList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ParameterList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.ParameterDeclaration.Position() +} + +// ParameterTypeListCase represents case numbers of production ParameterTypeList +type ParameterTypeListCase int + +// Values of type ParameterTypeListCase +const ( + ParameterTypeListList ParameterTypeListCase = iota + ParameterTypeListVar +) + +// String implements fmt.Stringer +func (n ParameterTypeListCase) String() string { + switch n { + case ParameterTypeListList: + return "ParameterTypeListList" + case ParameterTypeListVar: + return "ParameterTypeListVar" + default: + return fmt.Sprintf("ParameterTypeListCase(%v)", int(n)) + } +} + +// ParameterTypeList represents data reduced by productions: +// +// ParameterTypeList: +// ParameterList // Case ParameterTypeListList +// | ParameterList ',' "..." // Case ParameterTypeListVar +type ParameterTypeList struct { + Case ParameterTypeListCase `PrettyPrint:"stringer,zero"` + ParameterList *ParameterList + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *ParameterTypeList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ParameterTypeList) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.ParameterList.Position() + case 1: + if p := n.ParameterList.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + default: + panic("internal error") + } +} + +// PointerCase represents case numbers of production Pointer +type PointerCase int + +// Values of type PointerCase +const ( + PointerTypeQual PointerCase = iota + PointerPtr + PointerBlock +) + +// String implements fmt.Stringer +func (n PointerCase) String() string { + switch n { + case PointerTypeQual: + return "PointerTypeQual" + case PointerPtr: + return "PointerPtr" + case PointerBlock: + return "PointerBlock" + default: + return fmt.Sprintf("PointerCase(%v)", int(n)) + } +} + +// Pointer represents data reduced by productions: +// +// Pointer: +// '*' TypeQualifiers // Case PointerTypeQual +// | '*' TypeQualifiers Pointer // Case PointerPtr +// | '^' TypeQualifiers // Case PointerBlock +type Pointer struct { + typeQualifiers *typeBase + Case PointerCase `PrettyPrint:"stringer,zero"` + Pointer *Pointer + Token Token + TypeQualifiers *TypeQualifiers +} + +// String implements fmt.Stringer. +func (n *Pointer) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Pointer) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0, 2: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.TypeQualifiers.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + return n.Pointer.Position() + default: + panic("internal error") + } +} + +// PostfixExpressionCase represents case numbers of production PostfixExpression +type PostfixExpressionCase int + +// Values of type PostfixExpressionCase +const ( + PostfixExpressionPrimary PostfixExpressionCase = iota + PostfixExpressionIndex + PostfixExpressionCall + PostfixExpressionSelect + PostfixExpressionPSelect + PostfixExpressionInc + PostfixExpressionDec + PostfixExpressionComplit + PostfixExpressionTypeCmp + PostfixExpressionChooseExpr +) + +// String implements fmt.Stringer +func (n PostfixExpressionCase) String() string { + switch n { + case PostfixExpressionPrimary: + return "PostfixExpressionPrimary" + case PostfixExpressionIndex: + return "PostfixExpressionIndex" + case PostfixExpressionCall: + return "PostfixExpressionCall" + case PostfixExpressionSelect: + return "PostfixExpressionSelect" + case PostfixExpressionPSelect: + return "PostfixExpressionPSelect" + case PostfixExpressionInc: + return "PostfixExpressionInc" + case PostfixExpressionDec: + return "PostfixExpressionDec" + case PostfixExpressionComplit: + return "PostfixExpressionComplit" + case PostfixExpressionTypeCmp: + return "PostfixExpressionTypeCmp" + case PostfixExpressionChooseExpr: + return "PostfixExpressionChooseExpr" + default: + return fmt.Sprintf("PostfixExpressionCase(%v)", int(n)) + } +} + +// PostfixExpression represents data reduced by productions: +// +// PostfixExpression: +// PrimaryExpression // Case PostfixExpressionPrimary +// | PostfixExpression '[' Expression ']' // Case PostfixExpressionIndex +// | PostfixExpression '(' ArgumentExpressionList ')' // Case PostfixExpressionCall +// | PostfixExpression '.' IDENTIFIER // Case PostfixExpressionSelect +// | PostfixExpression "->" IDENTIFIER // Case PostfixExpressionPSelect +// | PostfixExpression "++" // Case PostfixExpressionInc +// | PostfixExpression "--" // Case PostfixExpressionDec +// | '(' TypeName ')' '{' InitializerList ',' '}' // Case PostfixExpressionComplit +// | "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')' // Case PostfixExpressionTypeCmp +// | "__builtin_choose_expr" '(' AssignmentExpression ',' AssignmentExpression ',' AssignmentExpression ')' // Case PostfixExpressionChooseExpr +type PostfixExpression struct { + Operand Operand + Field Field // Case Select, PSelect + IsSideEffectsFree bool + ArgumentExpressionList *ArgumentExpressionList + AssignmentExpression *AssignmentExpression + AssignmentExpression2 *AssignmentExpression + AssignmentExpression3 *AssignmentExpression + Case PostfixExpressionCase `PrettyPrint:"stringer,zero"` + Expression *Expression + InitializerList *InitializerList + PostfixExpression *PostfixExpression + PrimaryExpression *PrimaryExpression + Token Token + Token2 Token + Token3 Token + Token4 Token + Token5 Token + TypeName *TypeName + TypeName2 *TypeName +} + +// String implements fmt.Stringer. +func (n *PostfixExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *PostfixExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 5, 6: + if p := n.PostfixExpression.Position(); p.IsValid() { + return p + } + + return n.Token.Position() + case 2: + if p := n.PostfixExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ArgumentExpressionList.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 1: + if p := n.PostfixExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 3, 4: + if p := n.PostfixExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 0: + return n.PrimaryExpression.Position() + case 9: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression2.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + if p := n.AssignmentExpression3.Position(); p.IsValid() { + return p + } + + return n.Token5.Position() + case 8: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.TypeName2.Position(); p.IsValid() { + return p + } + + return n.Token4.Position() + case 7: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.InitializerList.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + return n.Token5.Position() + default: + panic("internal error") + } +} + +// PragmaSTDC represents data reduced by production: +// +// PragmaSTDC: +// "__pragma_stdc" IDENTIFIER IDENTIFIER IDENTIFIER +type PragmaSTDC struct { + Token Token + Token2 Token + Token3 Token + Token4 Token +} + +// String implements fmt.Stringer. +func (n *PragmaSTDC) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *PragmaSTDC) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + return n.Token4.Position() +} + +// PrimaryExpressionCase represents case numbers of production PrimaryExpression +type PrimaryExpressionCase int + +// Values of type PrimaryExpressionCase +const ( + PrimaryExpressionIdent PrimaryExpressionCase = iota + PrimaryExpressionInt + PrimaryExpressionFloat + PrimaryExpressionEnum + PrimaryExpressionChar + PrimaryExpressionLChar + PrimaryExpressionString + PrimaryExpressionLString + PrimaryExpressionExpr + PrimaryExpressionStmt +) + +// String implements fmt.Stringer +func (n PrimaryExpressionCase) String() string { + switch n { + case PrimaryExpressionIdent: + return "PrimaryExpressionIdent" + case PrimaryExpressionInt: + return "PrimaryExpressionInt" + case PrimaryExpressionFloat: + return "PrimaryExpressionFloat" + case PrimaryExpressionEnum: + return "PrimaryExpressionEnum" + case PrimaryExpressionChar: + return "PrimaryExpressionChar" + case PrimaryExpressionLChar: + return "PrimaryExpressionLChar" + case PrimaryExpressionString: + return "PrimaryExpressionString" + case PrimaryExpressionLString: + return "PrimaryExpressionLString" + case PrimaryExpressionExpr: + return "PrimaryExpressionExpr" + case PrimaryExpressionStmt: + return "PrimaryExpressionStmt" + default: + return fmt.Sprintf("PrimaryExpressionCase(%v)", int(n)) + } +} + +// PrimaryExpression represents data reduced by productions: +// +// PrimaryExpression: +// IDENTIFIER // Case PrimaryExpressionIdent +// | INTCONST // Case PrimaryExpressionInt +// | FLOATCONST // Case PrimaryExpressionFloat +// | ENUMCONST // Case PrimaryExpressionEnum +// | CHARCONST // Case PrimaryExpressionChar +// | LONGCHARCONST // Case PrimaryExpressionLChar +// | STRINGLITERAL // Case PrimaryExpressionString +// | LONGSTRINGLITERAL // Case PrimaryExpressionLString +// | '(' Expression ')' // Case PrimaryExpressionExpr +// | '(' CompoundStatement ')' // Case PrimaryExpressionStmt +type PrimaryExpression struct { + Operand Operand + lexicalScope Scope + resolvedIn Scope + resolvedTo Node + IsSideEffectsFree bool + Case PrimaryExpressionCase `PrettyPrint:"stringer,zero"` + CompoundStatement *CompoundStatement + Expression *Expression + Token Token + Token2 Token +} + +// String implements fmt.Stringer. +func (n *PrimaryExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *PrimaryExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0, 1, 2, 3, 4, 5, 6, 7: + return n.Token.Position() + case 9: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.CompoundStatement.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 8: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + default: + panic("internal error") + } +} + +// RelationalExpressionCase represents case numbers of production RelationalExpression +type RelationalExpressionCase int + +// Values of type RelationalExpressionCase +const ( + RelationalExpressionShift RelationalExpressionCase = iota + RelationalExpressionLt + RelationalExpressionGt + RelationalExpressionLeq + RelationalExpressionGeq +) + +// String implements fmt.Stringer +func (n RelationalExpressionCase) String() string { + switch n { + case RelationalExpressionShift: + return "RelationalExpressionShift" + case RelationalExpressionLt: + return "RelationalExpressionLt" + case RelationalExpressionGt: + return "RelationalExpressionGt" + case RelationalExpressionLeq: + return "RelationalExpressionLeq" + case RelationalExpressionGeq: + return "RelationalExpressionGeq" + default: + return fmt.Sprintf("RelationalExpressionCase(%v)", int(n)) + } +} + +// RelationalExpression represents data reduced by productions: +// +// RelationalExpression: +// ShiftExpression // Case RelationalExpressionShift +// | RelationalExpression '<' ShiftExpression // Case RelationalExpressionLt +// | RelationalExpression '>' ShiftExpression // Case RelationalExpressionGt +// | RelationalExpression "<=" ShiftExpression // Case RelationalExpressionLeq +// | RelationalExpression ">=" ShiftExpression // Case RelationalExpressionGeq +type RelationalExpression struct { + Operand Operand + promote Type + IsSideEffectsFree bool + Case RelationalExpressionCase `PrettyPrint:"stringer,zero"` + RelationalExpression *RelationalExpression + ShiftExpression *ShiftExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *RelationalExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *RelationalExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1, 2, 3, 4: + if p := n.RelationalExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.ShiftExpression.Position() + case 0: + return n.ShiftExpression.Position() + default: + panic("internal error") + } +} + +// SelectionStatementCase represents case numbers of production SelectionStatement +type SelectionStatementCase int + +// Values of type SelectionStatementCase +const ( + SelectionStatementIf SelectionStatementCase = iota + SelectionStatementIfElse + SelectionStatementSwitch +) + +// String implements fmt.Stringer +func (n SelectionStatementCase) String() string { + switch n { + case SelectionStatementIf: + return "SelectionStatementIf" + case SelectionStatementIfElse: + return "SelectionStatementIfElse" + case SelectionStatementSwitch: + return "SelectionStatementSwitch" + default: + return fmt.Sprintf("SelectionStatementCase(%v)", int(n)) + } +} + +// SelectionStatement represents data reduced by productions: +// +// SelectionStatement: +// "if" '(' Expression ')' Statement // Case SelectionStatementIf +// | "if" '(' Expression ')' Statement "else" Statement // Case SelectionStatementIfElse +// | "switch" '(' Expression ')' Statement // Case SelectionStatementSwitch +type SelectionStatement struct { + promote Type // switch expression promoted type + cases []*LabeledStatement + Case SelectionStatementCase `PrettyPrint:"stringer,zero"` + Expression *Expression + Statement *Statement + Statement2 *Statement + Token Token + Token2 Token + Token3 Token + Token4 Token +} + +// String implements fmt.Stringer. +func (n *SelectionStatement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *SelectionStatement) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0, 2: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + return n.Statement.Position() + case 1: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + if p := n.Token3.Position(); p.IsValid() { + return p + } + + if p := n.Statement.Position(); p.IsValid() { + return p + } + + if p := n.Token4.Position(); p.IsValid() { + return p + } + + return n.Statement2.Position() + default: + panic("internal error") + } +} + +// ShiftExpressionCase represents case numbers of production ShiftExpression +type ShiftExpressionCase int + +// Values of type ShiftExpressionCase +const ( + ShiftExpressionAdd ShiftExpressionCase = iota + ShiftExpressionLsh + ShiftExpressionRsh +) + +// String implements fmt.Stringer +func (n ShiftExpressionCase) String() string { + switch n { + case ShiftExpressionAdd: + return "ShiftExpressionAdd" + case ShiftExpressionLsh: + return "ShiftExpressionLsh" + case ShiftExpressionRsh: + return "ShiftExpressionRsh" + default: + return fmt.Sprintf("ShiftExpressionCase(%v)", int(n)) + } +} + +// ShiftExpression represents data reduced by productions: +// +// ShiftExpression: +// AdditiveExpression // Case ShiftExpressionAdd +// | ShiftExpression "<<" AdditiveExpression // Case ShiftExpressionLsh +// | ShiftExpression ">>" AdditiveExpression // Case ShiftExpressionRsh +type ShiftExpression struct { + Operand Operand + promote Type // shift count promoted type + IsSideEffectsFree bool + AdditiveExpression *AdditiveExpression + Case ShiftExpressionCase `PrettyPrint:"stringer,zero"` + ShiftExpression *ShiftExpression + Token Token +} + +// String implements fmt.Stringer. +func (n *ShiftExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *ShiftExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.AdditiveExpression.Position() + case 1, 2: + if p := n.ShiftExpression.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.AdditiveExpression.Position() + default: + panic("internal error") + } +} + +// SpecifierQualifierListCase represents case numbers of production SpecifierQualifierList +type SpecifierQualifierListCase int + +// Values of type SpecifierQualifierListCase +const ( + SpecifierQualifierListTypeSpec SpecifierQualifierListCase = iota + SpecifierQualifierListTypeQual + SpecifierQualifierListAlignSpec + SpecifierQualifierListAttribute +) + +// String implements fmt.Stringer +func (n SpecifierQualifierListCase) String() string { + switch n { + case SpecifierQualifierListTypeSpec: + return "SpecifierQualifierListTypeSpec" + case SpecifierQualifierListTypeQual: + return "SpecifierQualifierListTypeQual" + case SpecifierQualifierListAlignSpec: + return "SpecifierQualifierListAlignSpec" + case SpecifierQualifierListAttribute: + return "SpecifierQualifierListAttribute" + default: + return fmt.Sprintf("SpecifierQualifierListCase(%v)", int(n)) + } +} + +// SpecifierQualifierList represents data reduced by productions: +// +// SpecifierQualifierList: +// TypeSpecifier SpecifierQualifierList // Case SpecifierQualifierListTypeSpec +// | TypeQualifier SpecifierQualifierList // Case SpecifierQualifierListTypeQual +// | AlignmentSpecifier SpecifierQualifierList // Case SpecifierQualifierListAlignSpec +// | AttributeSpecifier SpecifierQualifierList // Case SpecifierQualifierListAttribute +type SpecifierQualifierList struct { + noStorageClass + AlignmentSpecifier *AlignmentSpecifier + AttributeSpecifier *AttributeSpecifier + Case SpecifierQualifierListCase `PrettyPrint:"stringer,zero"` + SpecifierQualifierList *SpecifierQualifierList + TypeQualifier *TypeQualifier + TypeSpecifier *TypeSpecifier +} + +// String implements fmt.Stringer. +func (n *SpecifierQualifierList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *SpecifierQualifierList) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 2: + if p := n.AlignmentSpecifier.Position(); p.IsValid() { + return p + } + + return n.SpecifierQualifierList.Position() + case 3: + if p := n.AttributeSpecifier.Position(); p.IsValid() { + return p + } + + return n.SpecifierQualifierList.Position() + case 1: + if p := n.TypeQualifier.Position(); p.IsValid() { + return p + } + + return n.SpecifierQualifierList.Position() + case 0: + if p := n.TypeSpecifier.Position(); p.IsValid() { + return p + } + + return n.SpecifierQualifierList.Position() + default: + panic("internal error") + } +} + +// StatementCase represents case numbers of production Statement +type StatementCase int + +// Values of type StatementCase +const ( + StatementLabeled StatementCase = iota + StatementCompound + StatementExpr + StatementSelection + StatementIteration + StatementJump + StatementAsm +) + +// String implements fmt.Stringer +func (n StatementCase) String() string { + switch n { + case StatementLabeled: + return "StatementLabeled" + case StatementCompound: + return "StatementCompound" + case StatementExpr: + return "StatementExpr" + case StatementSelection: + return "StatementSelection" + case StatementIteration: + return "StatementIteration" + case StatementJump: + return "StatementJump" + case StatementAsm: + return "StatementAsm" + default: + return fmt.Sprintf("StatementCase(%v)", int(n)) + } +} + +// Statement represents data reduced by productions: +// +// Statement: +// LabeledStatement // Case StatementLabeled +// | CompoundStatement // Case StatementCompound +// | ExpressionStatement // Case StatementExpr +// | SelectionStatement // Case StatementSelection +// | IterationStatement // Case StatementIteration +// | JumpStatement // Case StatementJump +// | AsmStatement // Case StatementAsm +type Statement struct { + Operand Operand // Case CompoundStatement, ExpressionStatement + AsmStatement *AsmStatement + Case StatementCase `PrettyPrint:"stringer,zero"` + CompoundStatement *CompoundStatement + ExpressionStatement *ExpressionStatement + IterationStatement *IterationStatement + JumpStatement *JumpStatement + LabeledStatement *LabeledStatement + SelectionStatement *SelectionStatement +} + +// String implements fmt.Stringer. +func (n *Statement) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *Statement) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 6: + return n.AsmStatement.Position() + case 1: + return n.CompoundStatement.Position() + case 2: + return n.ExpressionStatement.Position() + case 4: + return n.IterationStatement.Position() + case 5: + return n.JumpStatement.Position() + case 0: + return n.LabeledStatement.Position() + case 3: + return n.SelectionStatement.Position() + default: + panic("internal error") + } +} + +// StorageClassSpecifierCase represents case numbers of production StorageClassSpecifier +type StorageClassSpecifierCase int + +// Values of type StorageClassSpecifierCase +const ( + StorageClassSpecifierTypedef StorageClassSpecifierCase = iota + StorageClassSpecifierExtern + StorageClassSpecifierStatic + StorageClassSpecifierAuto + StorageClassSpecifierRegister + StorageClassSpecifierThreadLocal +) + +// String implements fmt.Stringer +func (n StorageClassSpecifierCase) String() string { + switch n { + case StorageClassSpecifierTypedef: + return "StorageClassSpecifierTypedef" + case StorageClassSpecifierExtern: + return "StorageClassSpecifierExtern" + case StorageClassSpecifierStatic: + return "StorageClassSpecifierStatic" + case StorageClassSpecifierAuto: + return "StorageClassSpecifierAuto" + case StorageClassSpecifierRegister: + return "StorageClassSpecifierRegister" + case StorageClassSpecifierThreadLocal: + return "StorageClassSpecifierThreadLocal" + default: + return fmt.Sprintf("StorageClassSpecifierCase(%v)", int(n)) + } +} + +// StorageClassSpecifier represents data reduced by productions: +// +// StorageClassSpecifier: +// "typedef" // Case StorageClassSpecifierTypedef +// | "extern" // Case StorageClassSpecifierExtern +// | "static" // Case StorageClassSpecifierStatic +// | "auto" // Case StorageClassSpecifierAuto +// | "register" // Case StorageClassSpecifierRegister +// | "_Thread_local" // Case StorageClassSpecifierThreadLocal +type StorageClassSpecifier struct { + Case StorageClassSpecifierCase `PrettyPrint:"stringer,zero"` + Token Token +} + +// String implements fmt.Stringer. +func (n *StorageClassSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StorageClassSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Token.Position() +} + +// StructDeclaration represents data reduced by production: +// +// StructDeclaration: +// SpecifierQualifierList StructDeclaratorList ';' +type StructDeclaration struct { + Empty bool // TCC extension + SpecifierQualifierList *SpecifierQualifierList + StructDeclaratorList *StructDeclaratorList + Token Token +} + +// String implements fmt.Stringer. +func (n *StructDeclaration) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StructDeclaration) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.SpecifierQualifierList.Position(); p.IsValid() { + return p + } + + if p := n.StructDeclaratorList.Position(); p.IsValid() { + return p + } + + return n.Token.Position() +} + +// StructDeclarationList represents data reduced by productions: +// +// StructDeclarationList: +// StructDeclaration +// | StructDeclarationList StructDeclaration +type StructDeclarationList struct { + StructDeclaration *StructDeclaration + StructDeclarationList *StructDeclarationList +} + +// String implements fmt.Stringer. +func (n *StructDeclarationList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StructDeclarationList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.StructDeclaration.Position() +} + +// StructDeclaratorCase represents case numbers of production StructDeclarator +type StructDeclaratorCase int + +// Values of type StructDeclaratorCase +const ( + StructDeclaratorDecl StructDeclaratorCase = iota + StructDeclaratorBitField +) + +// String implements fmt.Stringer +func (n StructDeclaratorCase) String() string { + switch n { + case StructDeclaratorDecl: + return "StructDeclaratorDecl" + case StructDeclaratorBitField: + return "StructDeclaratorBitField" + default: + return fmt.Sprintf("StructDeclaratorCase(%v)", int(n)) + } +} + +// StructDeclarator represents data reduced by productions: +// +// StructDeclarator: +// Declarator // Case StructDeclaratorDecl +// | Declarator ':' ConstantExpression AttributeSpecifierList // Case StructDeclaratorBitField +type StructDeclarator struct { + decl *StructDeclaration + AttributeSpecifierList *AttributeSpecifierList + Case StructDeclaratorCase `PrettyPrint:"stringer,zero"` + ConstantExpression *ConstantExpression + Declarator *Declarator + Token Token +} + +// String implements fmt.Stringer. +func (n *StructDeclarator) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StructDeclarator) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.Declarator.Position() + case 1: + if p := n.Declarator.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.ConstantExpression.Position(); p.IsValid() { + return p + } + + return n.AttributeSpecifierList.Position() + default: + panic("internal error") + } +} + +// StructDeclaratorList represents data reduced by productions: +// +// StructDeclaratorList: +// StructDeclarator +// | StructDeclaratorList ',' StructDeclarator +type StructDeclaratorList struct { + StructDeclarator *StructDeclarator + StructDeclaratorList *StructDeclaratorList + Token Token +} + +// String implements fmt.Stringer. +func (n *StructDeclaratorList) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StructDeclaratorList) Position() (r token.Position) { + if n == nil { + return r + } + + return n.StructDeclarator.Position() +} + +// StructOrUnionCase represents case numbers of production StructOrUnion +type StructOrUnionCase int + +// Values of type StructOrUnionCase +const ( + StructOrUnionStruct StructOrUnionCase = iota + StructOrUnionUnion +) + +// String implements fmt.Stringer +func (n StructOrUnionCase) String() string { + switch n { + case StructOrUnionStruct: + return "StructOrUnionStruct" + case StructOrUnionUnion: + return "StructOrUnionUnion" + default: + return fmt.Sprintf("StructOrUnionCase(%v)", int(n)) + } +} + +// StructOrUnion represents data reduced by productions: +// +// StructOrUnion: +// "struct" // Case StructOrUnionStruct +// | "union" // Case StructOrUnionUnion +type StructOrUnion struct { + Case StructOrUnionCase `PrettyPrint:"stringer,zero"` + Token Token +} + +// String implements fmt.Stringer. +func (n *StructOrUnion) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StructOrUnion) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Token.Position() +} + +// StructOrUnionSpecifierCase represents case numbers of production StructOrUnionSpecifier +type StructOrUnionSpecifierCase int + +// Values of type StructOrUnionSpecifierCase +const ( + StructOrUnionSpecifierDef StructOrUnionSpecifierCase = iota + StructOrUnionSpecifierTag +) + +// String implements fmt.Stringer +func (n StructOrUnionSpecifierCase) String() string { + switch n { + case StructOrUnionSpecifierDef: + return "StructOrUnionSpecifierDef" + case StructOrUnionSpecifierTag: + return "StructOrUnionSpecifierTag" + default: + return fmt.Sprintf("StructOrUnionSpecifierCase(%v)", int(n)) + } +} + +// StructOrUnionSpecifier represents data reduced by productions: +// +// StructOrUnionSpecifier: +// StructOrUnion AttributeSpecifierList IDENTIFIER '{' StructDeclarationList '}' // Case StructOrUnionSpecifierDef +// | StructOrUnion AttributeSpecifierList IDENTIFIER // Case StructOrUnionSpecifierTag +type StructOrUnionSpecifier struct { + lexicalScope Scope + maxAlign int + typ Type + AttributeSpecifierList *AttributeSpecifierList + Case StructOrUnionSpecifierCase `PrettyPrint:"stringer,zero"` + StructDeclarationList *StructDeclarationList + StructOrUnion *StructOrUnion + Token Token + Token2 Token + Token3 Token +} + +// String implements fmt.Stringer. +func (n *StructOrUnionSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *StructOrUnionSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + if p := n.StructOrUnion.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + return n.Token.Position() + case 0: + if p := n.StructOrUnion.Position(); p.IsValid() { + return p + } + + if p := n.AttributeSpecifierList.Position(); p.IsValid() { + return p + } + + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.StructDeclarationList.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + default: + panic("internal error") + } +} + +// TranslationUnit represents data reduced by productions: +// +// TranslationUnit: +// ExternalDeclaration +// | TranslationUnit ExternalDeclaration +type TranslationUnit struct { + ExternalDeclaration *ExternalDeclaration + TranslationUnit *TranslationUnit +} + +// String implements fmt.Stringer. +func (n *TranslationUnit) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *TranslationUnit) Position() (r token.Position) { + if n == nil { + return r + } + + return n.ExternalDeclaration.Position() +} + +// TypeName represents data reduced by production: +// +// TypeName: +// SpecifierQualifierList AbstractDeclarator +type TypeName struct { + typ Type + AbstractDeclarator *AbstractDeclarator + SpecifierQualifierList *SpecifierQualifierList +} + +// String implements fmt.Stringer. +func (n *TypeName) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *TypeName) Position() (r token.Position) { + if n == nil { + return r + } + + if p := n.SpecifierQualifierList.Position(); p.IsValid() { + return p + } + + return n.AbstractDeclarator.Position() +} + +// TypeQualifierCase represents case numbers of production TypeQualifier +type TypeQualifierCase int + +// Values of type TypeQualifierCase +const ( + TypeQualifierConst TypeQualifierCase = iota + TypeQualifierRestrict + TypeQualifierVolatile + TypeQualifierAtomic +) + +// String implements fmt.Stringer +func (n TypeQualifierCase) String() string { + switch n { + case TypeQualifierConst: + return "TypeQualifierConst" + case TypeQualifierRestrict: + return "TypeQualifierRestrict" + case TypeQualifierVolatile: + return "TypeQualifierVolatile" + case TypeQualifierAtomic: + return "TypeQualifierAtomic" + default: + return fmt.Sprintf("TypeQualifierCase(%v)", int(n)) + } +} + +// TypeQualifier represents data reduced by productions: +// +// TypeQualifier: +// "const" // Case TypeQualifierConst +// | "restrict" // Case TypeQualifierRestrict +// | "volatile" // Case TypeQualifierVolatile +// | "_Atomic" // Case TypeQualifierAtomic +type TypeQualifier struct { + Case TypeQualifierCase `PrettyPrint:"stringer,zero"` + Token Token +} + +// String implements fmt.Stringer. +func (n *TypeQualifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *TypeQualifier) Position() (r token.Position) { + if n == nil { + return r + } + + return n.Token.Position() +} + +// TypeQualifiersCase represents case numbers of production TypeQualifiers +type TypeQualifiersCase int + +// Values of type TypeQualifiersCase +const ( + TypeQualifiersTypeQual TypeQualifiersCase = iota + TypeQualifiersAttribute + _ + _ +) + +// String implements fmt.Stringer +func (n TypeQualifiersCase) String() string { + switch n { + case TypeQualifiersTypeQual: + return "TypeQualifiersTypeQual" + case TypeQualifiersAttribute: + return "TypeQualifiersAttribute" + default: + return fmt.Sprintf("TypeQualifiersCase(%v)", int(n)) + } +} + +// TypeQualifiers represents data reduced by productions: +// +// TypeQualifiers: +// TypeQualifier // Case TypeQualifiersTypeQual +// | AttributeSpecifier // Case TypeQualifiersAttribute +// | TypeQualifiers TypeQualifier // Case 2 +// | TypeQualifiers AttributeSpecifier // Case 3 +type TypeQualifiers struct { + noStorageClass + AttributeSpecifier *AttributeSpecifier + Case TypeQualifiersCase `PrettyPrint:"stringer,zero"` + TypeQualifier *TypeQualifier + TypeQualifiers *TypeQualifiers +} + +// String implements fmt.Stringer. +func (n *TypeQualifiers) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *TypeQualifiers) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 1: + return n.AttributeSpecifier.Position() + case 0: + return n.TypeQualifier.Position() + case 3: + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + return n.AttributeSpecifier.Position() + case 2: + if p := n.TypeQualifiers.Position(); p.IsValid() { + return p + } + + return n.TypeQualifier.Position() + default: + panic("internal error") + } +} + +// TypeSpecifierCase represents case numbers of production TypeSpecifier +type TypeSpecifierCase int + +// Values of type TypeSpecifierCase +const ( + TypeSpecifierVoid TypeSpecifierCase = iota + TypeSpecifierChar + TypeSpecifierShort + TypeSpecifierInt + TypeSpecifierInt8 + TypeSpecifierInt16 + TypeSpecifierInt32 + TypeSpecifierInt64 + TypeSpecifierInt128 + TypeSpecifierLong + TypeSpecifierFloat + TypeSpecifierFloat16 + TypeSpecifierDecimal32 + TypeSpecifierDecimal64 + TypeSpecifierDecimal128 + TypeSpecifierFloat128 + TypeSpecifierFloat80 + TypeSpecifierDouble + TypeSpecifierSigned + TypeSpecifierUnsigned + TypeSpecifierBool + TypeSpecifierComplex + TypeSpecifierStructOrUnion + TypeSpecifierEnum + TypeSpecifierTypedefName + TypeSpecifierTypeofExpr + TypeSpecifierTypeofType + TypeSpecifierAtomic + TypeSpecifierFract + TypeSpecifierSat + TypeSpecifierAccum + TypeSpecifierFloat32 + TypeSpecifierFloat64 + TypeSpecifierFloat32x + TypeSpecifierFloat64x +) + +// String implements fmt.Stringer +func (n TypeSpecifierCase) String() string { + switch n { + case TypeSpecifierVoid: + return "TypeSpecifierVoid" + case TypeSpecifierChar: + return "TypeSpecifierChar" + case TypeSpecifierShort: + return "TypeSpecifierShort" + case TypeSpecifierInt: + return "TypeSpecifierInt" + case TypeSpecifierInt8: + return "TypeSpecifierInt8" + case TypeSpecifierInt16: + return "TypeSpecifierInt16" + case TypeSpecifierInt32: + return "TypeSpecifierInt32" + case TypeSpecifierInt64: + return "TypeSpecifierInt64" + case TypeSpecifierInt128: + return "TypeSpecifierInt128" + case TypeSpecifierLong: + return "TypeSpecifierLong" + case TypeSpecifierFloat: + return "TypeSpecifierFloat" + case TypeSpecifierFloat16: + return "TypeSpecifierFloat16" + case TypeSpecifierDecimal32: + return "TypeSpecifierDecimal32" + case TypeSpecifierDecimal64: + return "TypeSpecifierDecimal64" + case TypeSpecifierDecimal128: + return "TypeSpecifierDecimal128" + case TypeSpecifierFloat128: + return "TypeSpecifierFloat128" + case TypeSpecifierFloat80: + return "TypeSpecifierFloat80" + case TypeSpecifierDouble: + return "TypeSpecifierDouble" + case TypeSpecifierSigned: + return "TypeSpecifierSigned" + case TypeSpecifierUnsigned: + return "TypeSpecifierUnsigned" + case TypeSpecifierBool: + return "TypeSpecifierBool" + case TypeSpecifierComplex: + return "TypeSpecifierComplex" + case TypeSpecifierStructOrUnion: + return "TypeSpecifierStructOrUnion" + case TypeSpecifierEnum: + return "TypeSpecifierEnum" + case TypeSpecifierTypedefName: + return "TypeSpecifierTypedefName" + case TypeSpecifierTypeofExpr: + return "TypeSpecifierTypeofExpr" + case TypeSpecifierTypeofType: + return "TypeSpecifierTypeofType" + case TypeSpecifierAtomic: + return "TypeSpecifierAtomic" + case TypeSpecifierFract: + return "TypeSpecifierFract" + case TypeSpecifierSat: + return "TypeSpecifierSat" + case TypeSpecifierAccum: + return "TypeSpecifierAccum" + case TypeSpecifierFloat32: + return "TypeSpecifierFloat32" + case TypeSpecifierFloat64: + return "TypeSpecifierFloat64" + case TypeSpecifierFloat32x: + return "TypeSpecifierFloat32x" + case TypeSpecifierFloat64x: + return "TypeSpecifierFloat64x" + default: + return fmt.Sprintf("TypeSpecifierCase(%v)", int(n)) + } +} + +// TypeSpecifier represents data reduced by productions: +// +// TypeSpecifier: +// "void" // Case TypeSpecifierVoid +// | "char" // Case TypeSpecifierChar +// | "short" // Case TypeSpecifierShort +// | "int" // Case TypeSpecifierInt +// | "__int8" // Case TypeSpecifierInt8 +// | "__int16" // Case TypeSpecifierInt16 +// | "__int32" // Case TypeSpecifierInt32 +// | "__int64" // Case TypeSpecifierInt64 +// | "__int128" // Case TypeSpecifierInt128 +// | "long" // Case TypeSpecifierLong +// | "float" // Case TypeSpecifierFloat +// | "__fp16" // Case TypeSpecifierFloat16 +// | "_Decimal32" // Case TypeSpecifierDecimal32 +// | "_Decimal64" // Case TypeSpecifierDecimal64 +// | "_Decimal128" // Case TypeSpecifierDecimal128 +// | "_Float128" // Case TypeSpecifierFloat128 +// | "__float80" // Case TypeSpecifierFloat80 +// | "double" // Case TypeSpecifierDouble +// | "signed" // Case TypeSpecifierSigned +// | "unsigned" // Case TypeSpecifierUnsigned +// | "_Bool" // Case TypeSpecifierBool +// | "_Complex" // Case TypeSpecifierComplex +// | StructOrUnionSpecifier // Case TypeSpecifierStructOrUnion +// | EnumSpecifier // Case TypeSpecifierEnum +// | TYPEDEFNAME // Case TypeSpecifierTypedefName +// | "typeof" '(' Expression ')' // Case TypeSpecifierTypeofExpr +// | "typeof" '(' TypeName ')' // Case TypeSpecifierTypeofType +// | AtomicTypeSpecifier // Case TypeSpecifierAtomic +// | "_Fract" // Case TypeSpecifierFract +// | "_Sat" // Case TypeSpecifierSat +// | "_Accum" // Case TypeSpecifierAccum +// | "_Float32" // Case TypeSpecifierFloat32 +// | "_Float64" // Case TypeSpecifierFloat64 +// | "_Float32x" // Case TypeSpecifierFloat32x +// | "_Float64x" // Case TypeSpecifierFloat64x +type TypeSpecifier struct { + resolvedIn Scope // Case TypedefName + typ Type + AtomicTypeSpecifier *AtomicTypeSpecifier + Case TypeSpecifierCase `PrettyPrint:"stringer,zero"` + EnumSpecifier *EnumSpecifier + Expression *Expression + StructOrUnionSpecifier *StructOrUnionSpecifier + Token Token + Token2 Token + Token3 Token + TypeName *TypeName +} + +// String implements fmt.Stringer. +func (n *TypeSpecifier) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *TypeSpecifier) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 27: + return n.AtomicTypeSpecifier.Position() + case 23: + return n.EnumSpecifier.Position() + case 22: + return n.StructOrUnionSpecifier.Position() + case 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 24, 28, 29, 30, 31, 32, 33, 34: + return n.Token.Position() + case 25: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.Expression.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 26: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + default: + panic("internal error") + } +} + +// UnaryExpressionCase represents case numbers of production UnaryExpression +type UnaryExpressionCase int + +// Values of type UnaryExpressionCase +const ( + UnaryExpressionPostfix UnaryExpressionCase = iota + UnaryExpressionInc + UnaryExpressionDec + UnaryExpressionAddrof + UnaryExpressionDeref + UnaryExpressionPlus + UnaryExpressionMinus + UnaryExpressionCpl + UnaryExpressionNot + UnaryExpressionSizeofExpr + UnaryExpressionSizeofType + UnaryExpressionLabelAddr + UnaryExpressionAlignofExpr + UnaryExpressionAlignofType + UnaryExpressionImag + UnaryExpressionReal +) + +// String implements fmt.Stringer +func (n UnaryExpressionCase) String() string { + switch n { + case UnaryExpressionPostfix: + return "UnaryExpressionPostfix" + case UnaryExpressionInc: + return "UnaryExpressionInc" + case UnaryExpressionDec: + return "UnaryExpressionDec" + case UnaryExpressionAddrof: + return "UnaryExpressionAddrof" + case UnaryExpressionDeref: + return "UnaryExpressionDeref" + case UnaryExpressionPlus: + return "UnaryExpressionPlus" + case UnaryExpressionMinus: + return "UnaryExpressionMinus" + case UnaryExpressionCpl: + return "UnaryExpressionCpl" + case UnaryExpressionNot: + return "UnaryExpressionNot" + case UnaryExpressionSizeofExpr: + return "UnaryExpressionSizeofExpr" + case UnaryExpressionSizeofType: + return "UnaryExpressionSizeofType" + case UnaryExpressionLabelAddr: + return "UnaryExpressionLabelAddr" + case UnaryExpressionAlignofExpr: + return "UnaryExpressionAlignofExpr" + case UnaryExpressionAlignofType: + return "UnaryExpressionAlignofType" + case UnaryExpressionImag: + return "UnaryExpressionImag" + case UnaryExpressionReal: + return "UnaryExpressionReal" + default: + return fmt.Sprintf("UnaryExpressionCase(%v)", int(n)) + } +} + +// UnaryExpression represents data reduced by productions: +// +// UnaryExpression: +// PostfixExpression // Case UnaryExpressionPostfix +// | "++" UnaryExpression // Case UnaryExpressionInc +// | "--" UnaryExpression // Case UnaryExpressionDec +// | '&' CastExpression // Case UnaryExpressionAddrof +// | '*' CastExpression // Case UnaryExpressionDeref +// | '+' CastExpression // Case UnaryExpressionPlus +// | '-' CastExpression // Case UnaryExpressionMinus +// | '~' CastExpression // Case UnaryExpressionCpl +// | '!' CastExpression // Case UnaryExpressionNot +// | "sizeof" UnaryExpression // Case UnaryExpressionSizeofExpr +// | "sizeof" '(' TypeName ')' // Case UnaryExpressionSizeofType +// | "&&" IDENTIFIER // Case UnaryExpressionLabelAddr +// | "_Alignof" UnaryExpression // Case UnaryExpressionAlignofExpr +// | "_Alignof" '(' TypeName ')' // Case UnaryExpressionAlignofType +// | "__imag__" UnaryExpression // Case UnaryExpressionImag +// | "__real__" UnaryExpression // Case UnaryExpressionReal +type UnaryExpression struct { + Operand Operand + lexicalScope Scope + IsSideEffectsFree bool + Case UnaryExpressionCase `PrettyPrint:"stringer,zero"` + CastExpression *CastExpression + PostfixExpression *PostfixExpression + Token Token + Token2 Token + Token3 Token + TypeName *TypeName + UnaryExpression *UnaryExpression +} + +// String implements fmt.Stringer. +func (n *UnaryExpression) String() string { return PrettyString(n) } + +// Position reports the position of the first component of n, if available. +func (n *UnaryExpression) Position() (r token.Position) { + if n == nil { + return r + } + + switch n.Case { + case 0: + return n.PostfixExpression.Position() + case 3, 4, 5, 6, 7, 8: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.CastExpression.Position() + case 11: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.Token2.Position() + case 10, 13: + if p := n.Token.Position(); p.IsValid() { + return p + } + + if p := n.Token2.Position(); p.IsValid() { + return p + } + + if p := n.TypeName.Position(); p.IsValid() { + return p + } + + return n.Token3.Position() + case 1, 2, 9, 12, 14, 15: + if p := n.Token.Position(); p.IsValid() { + return p + } + + return n.UnaryExpression.Position() + default: + panic("internal error") + } +} diff --git a/vendor/modernc.org/cc/v3/ast2.go b/vendor/modernc.org/cc/v3/ast2.go new file mode 100644 index 00000000..13ed6130 --- /dev/null +++ b/vendor/modernc.org/cc/v3/ast2.go @@ -0,0 +1,1187 @@ +// 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" + "io" + "os" + "path/filepath" + "sort" + "strings" +) + +// Source is a named part of a translation unit. If Value is empty, Name is +// interpreted as a path to file containing the source code. +type Source struct { + Name string + Value string + DoNotCache bool // Disable caching of this source +} + +// Promote returns the type the operands of a binary operation are promoted to +// or the type and argument passed in a function call is promoted. +func (n *AssignmentExpression) Promote() Type { return n.promote } + +type StructInfo struct { + Size uintptr + + Align int +} + +// AST represents a translation unit and its related data. +type AST struct { + Enums map[StringID]Operand // Enumeration constants declared in file scope. + Macros map[StringID]*Macro // Macros as defined after parsing. + PtrdiffType Type + Scope Scope // File scope. + SizeType Type + StructTypes map[StringID]Type // Tagged struct/union types declared in file scope. + // Alignment and size of every struct/union defined in the translation + // unit. Valid only after Translate. + Structs map[StructInfo]struct{} + // TLD contains pruned file scope declarators, ie. either the first one + // or the first one that has an initializer. + TLD map[*Declarator]struct{} + TrailingSeperator StringID // White space and/or comments preceding EOF. + TranslationUnit *TranslationUnit + WideCharType Type + cfg *Config + cpp *cpp +} + +// Eval returns the operand that represents the value of m, if it expands to a +// valid constant expression other than an identifier, or an error, if any. +func (n *AST) Eval(m *Macro) (o Operand, err error) { + defer func() { + if e := recover(); e != nil { + o = nil + err = fmt.Errorf("%v", e) + } + }() + + if m.IsFnLike() { + return nil, fmt.Errorf("cannot evaluate function-like macro") + } + + n.cpp.ctx.cfg.ignoreErrors = true + n.cpp.ctx.evalIdentError = true + v := n.cpp.eval(m.repl) + switch x := v.(type) { + case int64: + return &operand{abi: &n.cfg.ABI, typ: n.cfg.ABI.Type(LongLong), value: Int64Value(x)}, nil + case uint64: + return &operand{abi: &n.cfg.ABI, typ: n.cfg.ABI.Type(ULongLong), value: Uint64Value(x)}, nil + default: + return nil, fmt.Errorf("unexpected value: %T", x) + } +} + +// Parse preprocesses and parses a translation unit and returns an *AST or +// error, if any. +// +// Search paths listed in includePaths and sysIncludePaths are used to resolve +// #include "foo.h" and #include <foo.h> preprocessing directives respectively. +// A special search path "@" is interpreted as 'the same directory as where the +// file with the #include directive is'. +// +// The sources should typically provide, usually in this particular order: +// +// - predefined macros, eg. +// +// #define __SIZE_TYPE__ long unsigned int +// +// - built-in declarations, eg. +// +// int __builtin_printf(char *__format, ...); +// +// - command-line provided directives, eg. +// +// #define FOO +// #define BAR 42 +// #undef QUX +// +// - normal C sources, eg. +// +// int main() {} +// +// All search and file paths should be absolute paths. +// +// If the preprocessed translation unit is empty, the function may return (nil, +// nil). +// +// The parser does only the minimum declarations/identifier resolving necessary +// for correct parsing. Redeclarations are not checked. +// +// Declarators (*Declarator) and StructDeclarators (*StructDeclarator) are +// inserted in the appropriate scopes. +// +// Tagged struct/union specifier definitions (*StructOrUnionSpecifier) are +// inserted in the appropriate scopes. +// +// Tagged enum specifier definitions (*EnumSpecifier) and enumeration constants +// (*Enumerator) are inserted in the appropriate scopes. +// +// Labels (*LabeledStatement) are inserted in the appropriate scopes. +func Parse(cfg *Config, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) { + return parse(newContext(cfg), includePaths, sysIncludePaths, sources) +} + +func parse(ctx *context, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) { + if s := ctx.cfg.SharedFunctionDefinitions; s != nil { + if s.M == nil { + s.M = map[*FunctionDefinition]struct{}{} + } + if s.m == nil { + s.m = map[sharedFunctionDefinitionKey]*FunctionDefinition{} + } + } + if debugWorkingDir || ctx.cfg.DebugWorkingDir { + switch wd, err := os.Getwd(); err { + case nil: + fmt.Fprintf(os.Stderr, "OS working dir: %s\n", wd) + default: + fmt.Fprintf(os.Stderr, "OS working dir: error %s\n", err) + } + fmt.Fprintf(os.Stderr, "Config.WorkingDir: %s\n", ctx.cfg.WorkingDir) + } + if debugIncludePaths || ctx.cfg.DebugIncludePaths { + fmt.Fprintf(os.Stderr, "include paths: %v\n", includePaths) + fmt.Fprintf(os.Stderr, "system include paths: %v\n", sysIncludePaths) + } + ctx.includePaths = includePaths + ctx.sysIncludePaths = sysIncludePaths + var in []source + for _, v := range sources { + ts, err := cache.get(ctx, v) + if err != nil { + return nil, err + } + + in = append(in, ts) + } + + p := newParser(ctx, make(chan *[]Token, 5000)) //DONE benchmark tuned + var sep StringID + var ssep []byte + var seq int32 + cpp := newCPP(ctx) + go func() { + + defer func() { + close(p.in) + ctx.intMaxWidth = cpp.intMaxWidth() + }() + + toks := tokenPool.Get().(*[]Token) + *toks = (*toks)[:0] + for pline := range cpp.translationPhase4(in) { + line := *pline + for _, tok := range line { + switch tok.char { + case ' ', '\n': + if ctx.cfg.PreserveOnlyLastNonBlankSeparator { + if strings.TrimSpace(tok.value.String()) != "" { + sep = tok.value + } + break + } + + switch { + case sep != 0: + ssep = append(ssep, tok.String()...) + default: + sep = tok.value + ssep = append(ssep[:0], sep.String()...) + } + default: + var t Token + t.Rune = tok.char + switch { + case len(ssep) != 0: + t.Sep = dict.id(ssep) + default: + t.Sep = sep + } + t.Value = tok.value + t.Src = tok.src + t.file = tok.file + t.macro = tok.macro + t.pos = tok.pos + seq++ + t.seq = seq + *toks = append(*toks, t) + sep = 0 + ssep = ssep[:0] + } + } + token4Pool.Put(pline) + var c rune + if n := len(*toks); n != 0 { + c = (*toks)[n-1].Rune + } + switch c { + case STRINGLITERAL, LONGSTRINGLITERAL: + // nop + default: + if len(*toks) != 0 { + p.in <- translationPhase5(ctx, toks) + toks = tokenPool.Get().(*[]Token) + *toks = (*toks)[:0] + } + } + } + if len(*toks) != 0 { + p.in <- translationPhase5(ctx, toks) + } + }() + + tu := p.translationUnit() + if p.errored { // Must drain + go func() { + for range p.in { + } + }() + } + + if err := ctx.Err(); err != nil { + return nil, err + } + + if p.errored && !ctx.cfg.ignoreErrors { + return nil, fmt.Errorf("%v: syntax error", p.tok.Position()) + } + + if p.scopes != 0 { + panic(internalErrorf("invalid scope nesting but no error reported")) + } + + ts := sep + if len(ssep) != 0 { + ts = dict.id(ssep) + } + return &AST{ + Macros: cpp.macros, + Scope: p.fileScope, + TLD: map[*Declarator]struct{}{}, + TrailingSeperator: ts, + TranslationUnit: tu, + cfg: ctx.cfg, + cpp: cpp, + }, nil +} + +func translationPhase5(ctx *context, toks *[]Token) *[]Token { + // [0], 5.1.1.2, 5 + // + // Each source character set member and escape sequence in character + // constants and string literals is converted to the corresponding + // member of the execution character set; if there is no corresponding + // member, it is converted to an implementation- defined member other + // than the null (wide) character. + for i, tok := range *toks { + var cpt cppToken + switch tok.Rune { + case STRINGLITERAL, LONGSTRINGLITERAL: + cpt.char = tok.Rune + cpt.value = tok.Value + cpt.src = tok.Src + cpt.file = tok.file + cpt.pos = tok.pos + (*toks)[i].Value = dict.sid(stringConst(ctx, cpt)) + case CHARCONST, LONGCHARCONST: + var cpt cppToken + cpt.char = tok.Rune + cpt.value = tok.Value + cpt.src = tok.Src + cpt.file = tok.file + cpt.pos = tok.pos + switch r := charConst(ctx, cpt); { + case r <= 255: + (*toks)[i].Value = dict.sid(string(r)) + default: + switch cpt.char { + case CHARCONST: + ctx.err(tok.Position(), "invalid character constant: %s", tok.Value) + default: + (*toks)[i].Value = dict.sid(string(r)) + } + } + } + } + return toks +} + +// Preprocess preprocesses a translation unit and outputs the result to w. +// +// Please see Parse for the documentation of the other parameters. +func Preprocess(cfg *Config, includePaths, sysIncludePaths []string, sources []Source, w io.Writer) error { + ctx := newContext(cfg) + if debugWorkingDir || ctx.cfg.DebugWorkingDir { + switch wd, err := os.Getwd(); err { + case nil: + fmt.Fprintf(os.Stderr, "OS working dir: %s\n", wd) + default: + fmt.Fprintf(os.Stderr, "OS working dir: error %s\n", err) + } + fmt.Fprintf(os.Stderr, "Config.WorkingDir: %s\n", ctx.cfg.WorkingDir) + } + if debugIncludePaths || ctx.cfg.DebugIncludePaths { + fmt.Fprintf(os.Stderr, "include paths: %v\n", includePaths) + fmt.Fprintf(os.Stderr, "system include paths: %v\n", sysIncludePaths) + } + ctx.includePaths = includePaths + ctx.sysIncludePaths = sysIncludePaths + var in []source + for _, v := range sources { + ts, err := cache.get(ctx, v) + if err != nil { + return err + } + + in = append(in, ts) + } + + var sep StringID + cpp := newCPP(ctx) + toks := tokenPool.Get().(*[]Token) + *toks = (*toks)[:0] + for pline := range cpp.translationPhase4(in) { + line := *pline + for _, tok := range line { + switch tok.char { + case ' ', '\n': + if ctx.cfg.PreserveOnlyLastNonBlankSeparator { + if strings.TrimSpace(tok.value.String()) != "" { + sep = tok.value + } + break + } + + switch { + case sep != 0: + sep = dict.sid(sep.String() + tok.String()) + default: + sep = tok.value + } + default: + var t Token + t.Rune = tok.char + t.Sep = sep + t.Value = tok.value + t.Src = tok.src + t.file = tok.file + t.pos = tok.pos + *toks = append(*toks, t) + sep = 0 + } + } + token4Pool.Put(pline) + var c rune + if n := len(*toks); n != 0 { + c = (*toks)[n-1].Rune + } + switch c { + case STRINGLITERAL, LONGSTRINGLITERAL: + // nop + default: + if len(*toks) != 0 { + for _, v := range *translationPhase5(ctx, toks) { + if err := wTok(w, v); err != nil { + return err + } + } + toks = tokenPool.Get().(*[]Token) + *toks = (*toks)[:0] + } + } + } + if len(*toks) != 0 { + for _, v := range *translationPhase5(ctx, toks) { + if err := wTok(w, v); err != nil { + return err + } + } + } + if _, err := fmt.Fprintln(w); err != nil { + return err + } + return ctx.Err() +} + +func wTok(w io.Writer, tok Token) (err error) { + switch tok.Rune { + case STRINGLITERAL, LONGSTRINGLITERAL: + _, err = fmt.Fprintf(w, `%s"%s"`, tok.Sep, cQuotedString(tok.String(), true)) + case CHARCONST, LONGCHARCONST: + _, err = fmt.Fprintf(w, `%s'%s'`, tok.Sep, cQuotedString(tok.String(), false)) + default: + _, err = fmt.Fprintf(w, "%s%s", tok.Sep, tok) + } + return err +} + +func cQuotedString(s string, isString bool) []byte { + var b []byte + for i := 0; i < len(s); i++ { + c := s[i] + switch c { + case '\b': + b = append(b, '\\', 'b') + continue + case '\f': + b = append(b, '\\', 'f') + continue + case '\n': + b = append(b, '\\', 'n') + continue + case '\r': + b = append(b, '\\', 'r') + continue + case '\t': + b = append(b, '\\', 't') + continue + case '\\': + b = append(b, '\\', '\\') + continue + case '"': + switch { + case isString: + b = append(b, '\\', '"') + default: + b = append(b, '"') + } + continue + case '\'': + switch { + case isString: + b = append(b, '\'') + default: + b = append(b, '\\', '\'') + } + continue + } + + switch { + case c < ' ' || c >= 0x7f: + b = append(b, '\\', octal(c>>6), octal(c>>3), octal(c)) + default: + b = append(b, c) + } + } + return b +} + +func octal(b byte) byte { return '0' + b&7 } + +var trcSource = Source{"<builtin-trc>", ` +extern void *stderr; +int fflush(void *stream); +int fprintf(void *stream, const char *format, ...); +`, false} + +// Translate parses and typechecks a translation unit and returns an *AST or +// error, if any. +// +// Please see Parse for the documentation of the parameters. +func Translate(cfg *Config, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) { + if cfg.InjectTracingCode { + for i, v := range sources { + if filepath.Ext(v.Name) == ".c" { + sources = append(append(append([]Source(nil), sources[:i]...), trcSource), sources[i:]...) + } + } + } + return translate(newContext(cfg), includePaths, sysIncludePaths, sources) +} + +func translate(ctx *context, includePaths, sysIncludePaths []string, sources []Source) (*AST, error) { + ast, err := parse(ctx, includePaths, sysIncludePaths, sources) + if err != nil { + return nil, err + } + + if ctx, err = ast.typecheck(); err != nil { + return nil, err + } + + ast.PtrdiffType = ptrdiffT(ctx, ast.Scope, Token{}) + ast.SizeType = sizeT(ctx, ast.Scope, Token{}) + ast.WideCharType = wcharT(ctx, ast.Scope, Token{}) + return ast, nil +} + +// Typecheck determines types of objects and expressions and verifies types are +// valid in the context they are used. +func (n *AST) Typecheck() error { + _, err := n.typecheck() + return err +} + +func (n *AST) typecheck() (*context, error) { + ctx := newContext(n.cfg) + if err := ctx.cfg.ABI.sanityCheck(ctx, int(ctx.intMaxWidth), n.Scope); err != nil { + return nil, err + } + + ctx.intBits = int(ctx.cfg.ABI.Types[Int].Size) * 8 + ctx.ast = n + n.TranslationUnit.check(ctx) + n.Structs = ctx.structs + var a []int + for k := range n.Scope { + a = append(a, int(k)) + } + sort.Ints(a) + for _, v := range a { + nm := StringID(v) + defs := n.Scope[nm] + var r, w int + for _, v := range defs { + switch x := v.(type) { + case *Declarator: + r += x.Read + w += x.Write + } + } + for _, v := range defs { + switch x := v.(type) { + case *Declarator: + x.Read = r + x.Write = w + } + } + var pruned *Declarator + for _, v := range defs { + switch x := v.(type) { + case *Declarator: + //TODO check compatible types + switch { + case x.IsExtern() && !x.fnDef: + // nop + case pruned == nil: + pruned = x + case pruned.hasInitializer && x.hasInitializer: + ctx.errNode(x, "multiple initializers for the same symbol") + continue + case pruned.fnDef && x.fnDef: + ctx.errNode(x, "multiple function definitions") + continue + case x.hasInitializer || x.fnDef: + pruned = x + } + } + } + if pruned == nil { + continue + } + + n.TLD[pruned] = struct{}{} + } + n.Enums = ctx.enums + n.StructTypes = ctx.structTypes + return ctx, ctx.Err() +} + +func (n *AlignmentSpecifier) align() int { + switch n.Case { + case AlignmentSpecifierAlignasType: // "_Alignas" '(' TypeName ')' + return n.TypeName.Type().Align() + case AlignmentSpecifierAlignasExpr: // "_Alignas" '(' ConstantExpression ')' + return n.ConstantExpression.Operand.Type().Align() + default: + panic(internalError()) + } +} + +// Closure reports the variables closed over by a nested function (case +// BlockItemFuncDef). +func (n *BlockItem) Closure() map[StringID]struct{} { return n.closure } + +// FunctionDefinition returns the nested function (case BlockItemFuncDef). +func (n *BlockItem) FunctionDefinition() *FunctionDefinition { return n.fn } + +func (n *Declarator) IsStatic() bool { return n.td != nil && n.td.static() } + +// IsImplicit reports whether n was not declared nor defined, only inferred. +func (n *Declarator) IsImplicit() bool { return n.implicit } + +func (n *Declarator) isVisible(at int32) bool { return at == 0 || n.DirectDeclarator.ends() < at } + +func (n *Declarator) setLHS(lhs *Declarator) { + if n == nil { + return + } + + if n.lhs == nil { + n.lhs = map[*Declarator]struct{}{} + } + n.lhs[lhs] = struct{}{} +} + +// LHS reports which declarators n is used in assignment RHS or which function +// declarators n is used in a function argument. To collect this information, +// TrackAssignments in Config must be set during type checking. +// The returned map may contain a nil key. That means that n is assigned to a +// declarator not known at typechecking time. +func (n *Declarator) LHS() map[*Declarator]struct{} { return n.lhs } + +// Called reports whether n is involved in expr in expr(callArgs). +func (n *Declarator) Called() bool { return n.called } + +// FunctionDefinition returns the function definition associated with n, if any. +func (n *Declarator) FunctionDefinition() *FunctionDefinition { + return n.funcDefinition +} + +// NameTok returns n's declaring name token. +func (n *Declarator) NameTok() (r Token) { + if n == nil || n.DirectDeclarator == nil { + return r + } + + return n.DirectDeclarator.NameTok() +} + +// LexicalScope returns the lexical scope of n. +func (n *Declarator) LexicalScope() Scope { return n.DirectDeclarator.lexicalScope } + +// Name returns n's declared name. +func (n *Declarator) Name() StringID { + if n == nil || n.DirectDeclarator == nil { + return 0 + } + + return n.DirectDeclarator.Name() +} + +// ParamScope returns the scope in which n's function parameters are declared +// if the underlying type of n is a function or nil otherwise. If n is part of +// a function definition the scope is the same as the scope of the function +// body. +func (n *Declarator) ParamScope() Scope { + if n == nil { + return nil + } + + return n.DirectDeclarator.ParamScope() +} + +// Type returns the type of n. +func (n *Declarator) Type() Type { return n.typ } + +// IsExtern reports whether n was declared with storage class specifier 'extern'. +func (n *Declarator) IsExtern() bool { return n.td != nil && n.td.extern() } + +func (n *DeclarationSpecifiers) auto() bool { return n != nil && n.class&fAuto != 0 } +func (n *DeclarationSpecifiers) extern() bool { return n != nil && n.class&fExtern != 0 } +func (n *DeclarationSpecifiers) register() bool { return n != nil && n.class&fRegister != 0 } +func (n *DeclarationSpecifiers) static() bool { return n != nil && n.class&fStatic != 0 } +func (n *DeclarationSpecifiers) threadLocal() bool { return n != nil && n.class&fThreadLocal != 0 } +func (n *DeclarationSpecifiers) typedef() bool { return n != nil && n.class&fTypedef != 0 } + +func (n *DirectAbstractDeclarator) TypeQualifier() Type { return n.typeQualifiers } + +func (n *DirectDeclarator) ends() int32 { + switch n.Case { + case DirectDeclaratorIdent: // IDENTIFIER + return n.Token.seq + case DirectDeclaratorDecl: // '(' Declarator ')' + return n.Token2.seq + case DirectDeclaratorArr: // DirectDeclarator '[' TypeQualifierList AssignmentExpression ']' + return n.Token2.seq + case DirectDeclaratorStaticArr: // DirectDeclarator '[' "static" TypeQualifierList AssignmentExpression ']' + return n.Token3.seq + case DirectDeclaratorArrStatic: // DirectDeclarator '[' TypeQualifierList "static" AssignmentExpression ']' + return n.Token3.seq + case DirectDeclaratorStar: // DirectDeclarator '[' TypeQualifierList '*' ']' + return n.Token3.seq + case DirectDeclaratorFuncParam: // DirectDeclarator '(' ParameterTypeList ')' + return n.Token2.seq + case DirectDeclaratorFuncIdent: // DirectDeclarator '(' IdentifierList ')' + return n.Token2.seq + default: + panic(internalError()) + } +} + +func (n *DirectDeclarator) TypeQualifier() Type { return n.typeQualifiers } + +// NameTok returns n's declarin name token. +func (n *DirectDeclarator) NameTok() (r Token) { + for { + if n == nil { + return r + } + + switch n.Case { + case DirectDeclaratorIdent: // IDENTIFIER + return n.Token + case DirectDeclaratorDecl: // '(' Declarator ')' + return n.Declarator.NameTok() + default: + n = n.DirectDeclarator + } + } +} + +// Name returns n's declared name. +func (n *DirectDeclarator) Name() StringID { + for { + if n == nil { + return 0 + } + + switch n.Case { + case DirectDeclaratorIdent: // IDENTIFIER + return n.Token.Value + case DirectDeclaratorDecl: // '(' Declarator ')' + return n.Declarator.Name() + default: + n = n.DirectDeclarator + } + } +} + +// ParamScope returns the innermost scope in which function parameters are +// declared for Case DirectDeclaratorFuncParam or DirectDeclaratorFuncIdent or +// nil otherwise. +func (n *DirectDeclarator) ParamScope() Scope { + if n == nil { + return nil + } + + switch n.Case { + case DirectDeclaratorIdent: // IDENTIFIER + return nil + case DirectDeclaratorDecl: // '(' Declarator ')' + return n.Declarator.ParamScope() + case DirectDeclaratorArr: // DirectDeclarator '[' TypeQualifierList AssignmentExpression ']' + return n.DirectDeclarator.ParamScope() + case DirectDeclaratorStaticArr: // DirectDeclarator '[' "static" TypeQualifierList AssignmentExpression ']' + return n.DirectDeclarator.ParamScope() + case DirectDeclaratorArrStatic: // DirectDeclarator '[' TypeQualifierList "static" AssignmentExpression ']' + return n.DirectDeclarator.ParamScope() + case DirectDeclaratorStar: // DirectDeclarator '[' TypeQualifierList '*' ']' + return n.DirectDeclarator.ParamScope() + case DirectDeclaratorFuncParam: // DirectDeclarator '(' ParameterTypeList ')' + if s := n.DirectDeclarator.ParamScope(); s != nil { + return s + } + + return n.paramScope + case DirectDeclaratorFuncIdent: // DirectDeclarator '(' IdentifierList ')' + if s := n.DirectDeclarator.ParamScope(); s != nil { + return s + } + + return n.paramScope + default: + panic(internalError()) + } +} + +func (n *Enumerator) isVisible(at int32) bool { return n.Token.seq < at } + +func (n *EnumSpecifier) Type() Type { return n.typ } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *EqualityExpression) Promote() Type { return n.promote } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *AdditiveExpression) Promote() Type { return n.promote } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *MultiplicativeExpression) Promote() Type { return n.promote } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *InclusiveOrExpression) Promote() Type { return n.promote } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *ExclusiveOrExpression) Promote() Type { return n.promote } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *AndExpression) Promote() Type { return n.promote } + +func (n *InitDeclarator) Value() *InitializerValue { return n.initializer } + +// FirstDesignatorField returns the first field a designator of an union type +// denotes, if any. +func (n *Initializer) FirstDesignatorField() Field { return n.field0 } + +// TrailingComma returns the comma token following n, if any. +func (n *Initializer) TrailingComma() *Token { return n.trailingComma } + +// IsConst reports whether n is constant. +func (n *Initializer) IsConst() bool { return n == nil || n.isConst } + +// IsZero reports whether n is a zero value. +func (n *Initializer) IsZero() bool { return n == nil || n.isZero } + +// List returns n as a flattened list of all items that are case +// InitializerExpr. +func (n *Initializer) List() []*Initializer { return n.list } + +// Parent returns the parent of n, if any. +func (n *Initializer) Parent() *Initializer { return n.parent } + +// Type returns the type this initializer initializes. +func (n *Initializer) Type() Type { return n.typ } + +// IsConst reports whether n is constant. +func (n *InitializerList) IsConst() bool { return n == nil || n.isConst } + +// IsZero reports whether n is a zero value. +func (n *InitializerList) IsZero() bool { return n == nil || n.isZero } + +// List returns n as a flattened list of all items that are case +// InitializerExpr. +func (n *InitializerList) List() []*Initializer { + if n == nil { + return nil + } + + return n.list +} + +// IsEmpty reprts whether n is an empty list. +func (n *InitializerList) IsEmpty() bool { return len(n.list) == 0 } + +// LexicalScope returns the lexical scope of n. +func (n *JumpStatement) LexicalScope() Scope { return n.lexicalScope } + +// LexicalScope returns the lexical scope of n. +func (n *LabeledStatement) LexicalScope() Scope { return n.lexicalScope } + +func (n *ParameterDeclaration) Type() Type { return n.typ } + +func (n *Pointer) TypeQualifier() Type { return n.typeQualifiers } + +// ResolvedIn reports which scope the identifier of cases +// PrimaryExpressionIdent, PrimaryExpressionEnum were resolved in, if any. +func (n *PrimaryExpression) ResolvedIn() Scope { return n.resolvedIn } + +// ResolvedTo reports which Node the identifier of cases +// PrimaryExpressionIdent, PrimaryExpressionEnum resolved to, if any. +func (n *PrimaryExpression) ResolvedTo() Node { return n.resolvedTo } + +// Promote returns the type the operands of the binary operation are promoted to. +func (n *RelationalExpression) Promote() Type { return n.promote } + +// Cases returns the cases a switch statement consist of, in source order. +func (n *SelectionStatement) Cases() []*LabeledStatement { return n.cases } + +// Promote returns the type the shift count operand is promoted to. +func (n *ShiftExpression) Promote() Type { return n.promote } + +func (n *StructOrUnionSpecifier) Type() Type { return n.typ } + +// Promote returns the type the type the switch expression is promoted to. +func (n *SelectionStatement) Promote() Type { return n.promote } + +// Type returns the type of n. +func (n *TypeName) Type() Type { return n.typ } + +// // LexicalScope returns the lexical scope of n. +// func (n *AttributeValue) LexicalScope() Scope { return n.lexicalScope } + +// // Scope returns n's scope. +// func (n *CompoundStatement) Scope() Scope { return n.scope } + +// // LexicalScope returns the lexical scope of n. +// func (n *Designator) LexicalScope() Scope { return n.lexicalScope } + +// // LexicalScope returns the lexical scope of n. +// func (n *DirectDeclarator) LexicalScope() Scope { return n.lexicalScope } + +// LexicalScope returns the lexical scope of n. +func (n *EnumSpecifier) LexicalScope() Scope { return n.lexicalScope } + +// // LexicalScope returns the lexical scope of n. +// func (n *IdentifierList) LexicalScope() Scope { return n.lexicalScope } + +// // LexicalScope returns the lexical scope of n. +// func (n *PrimaryExpression) LexicalScope() Scope { return n.lexicalScope } + +// // LexicalScope returns the lexical scope of n. +// func (n *StructOrUnionSpecifier) LexicalScope() Scope { return n.lexicalScope } + +// // ResolvedIn reports which scope the identifier of case +// // TypeSpecifierTypedefName was resolved in, if any. +// func (n *TypeSpecifier) ResolvedIn() Scope { return n.resolvedIn } + +func (n *TypeSpecifier) list() (r []*TypeSpecifier) { + switch n.Case { + case TypeSpecifierAtomic: + return n.AtomicTypeSpecifier.list + default: + return []*TypeSpecifier{n} + } +} + +// // LexicalScope returns the lexical scope of n. +// func (n *UnaryExpression) LexicalScope() Scope { return n.lexicalScope } + +func (n *UnaryExpression) Declarator() *Declarator { + switch n.Case { + case UnaryExpressionPostfix: // PostfixExpression + return n.PostfixExpression.Declarator() + default: + return nil + } +} + +func (n *PostfixExpression) Declarator() *Declarator { + switch n.Case { + case PostfixExpressionPrimary: // PrimaryExpression + return n.PrimaryExpression.Declarator() + default: + return nil + } +} + +func (n *PrimaryExpression) Declarator() *Declarator { + switch n.Case { + case PrimaryExpressionIdent: // IDENTIFIER + if n.Operand != nil { + return n.Operand.Declarator() + } + + return nil + case PrimaryExpressionExpr: // '(' Expression ')' + return n.Expression.Declarator() + default: + return nil + } +} + +func (n *Expression) Declarator() *Declarator { + switch n.Case { + case ExpressionAssign: // AssignmentExpression + return n.AssignmentExpression.Declarator() + default: + return nil + } +} + +func (n *AssignmentExpression) Declarator() *Declarator { + switch n.Case { + case AssignmentExpressionCond: // ConditionalExpression + return n.ConditionalExpression.Declarator() + default: + return nil + } +} + +func (n *ConditionalExpression) Declarator() *Declarator { + switch n.Case { + case ConditionalExpressionLOr: // LogicalOrExpression + return n.LogicalOrExpression.Declarator() + default: + return nil + } +} + +func (n *LogicalOrExpression) Declarator() *Declarator { + switch n.Case { + case LogicalOrExpressionLAnd: // LogicalAndExpression + return n.LogicalAndExpression.Declarator() + default: + return nil + } +} + +func (n *LogicalAndExpression) Declarator() *Declarator { + switch n.Case { + case LogicalAndExpressionOr: // InclusiveOrExpression + return n.InclusiveOrExpression.Declarator() + default: + return nil + } +} + +func (n *InclusiveOrExpression) Declarator() *Declarator { + switch n.Case { + case InclusiveOrExpressionXor: // ExclusiveOrExpression + return n.ExclusiveOrExpression.Declarator() + default: + return nil + } +} + +func (n *ExclusiveOrExpression) Declarator() *Declarator { + switch n.Case { + case ExclusiveOrExpressionAnd: // AndExpression + return n.AndExpression.Declarator() + default: + return nil + } +} + +func (n *AndExpression) Declarator() *Declarator { + switch n.Case { + case AndExpressionEq: // EqualityExpression + return n.EqualityExpression.Declarator() + default: + return nil + } +} + +func (n *EqualityExpression) Declarator() *Declarator { + switch n.Case { + case EqualityExpressionRel: // RelationalExpression + return n.RelationalExpression.Declarator() + default: + return nil + } +} + +func (n *RelationalExpression) Declarator() *Declarator { + switch n.Case { + case RelationalExpressionShift: // ShiftExpression + return n.ShiftExpression.Declarator() + default: + return nil + } +} + +func (n *ShiftExpression) Declarator() *Declarator { + switch n.Case { + case ShiftExpressionAdd: // AdditiveExpression + return n.AdditiveExpression.Declarator() + default: + return nil + } +} + +func (n *AdditiveExpression) Declarator() *Declarator { + switch n.Case { + case AdditiveExpressionMul: // MultiplicativeExpression + return n.MultiplicativeExpression.Declarator() + default: + return nil + } +} + +func (n *MultiplicativeExpression) Declarator() *Declarator { + switch n.Case { + case MultiplicativeExpressionCast: // CastExpression + return n.CastExpression.Declarator() + default: + return nil + } +} + +func (n *CastExpression) Declarator() *Declarator { + switch n.Case { + case CastExpressionUnary: // UnaryExpression + return n.UnaryExpression.Declarator() + default: + return nil + } +} + +// Has reports whether n has any of attributes in key. +func (n *AttributeSpecifier) Has(key ...StringID) (*ExpressionList, bool) { + if n == nil { + return nil, false + } + + for list := n.AttributeValueList; list != nil; list = list.AttributeValueList { + av := list.AttributeValue + for _, k := range key { + if av.Token.Value == k { + switch av.Case { + case AttributeValueIdent: // IDENTIFIER + return nil, true + case AttributeValueExpr: // IDENTIFIER '(' ExpressionList ')' + return av.ExpressionList, true + } + } + } + } + return nil, false +} + +// Has reports whether n has any of attributes in key. +func (n *AttributeSpecifierList) Has(key ...StringID) (*ExpressionList, bool) { + for ; n != nil; n = n.AttributeSpecifierList { + if exprList, ok := n.AttributeSpecifier.Has(key...); ok { + return exprList, ok + } + } + return nil, false +} + +// Parent returns the CompoundStatement that contains n, if any. +func (n *CompoundStatement) Parent() *CompoundStatement { return n.parent } + +// IsJumpTarget returns whether n or any of its children contain a named +// labeled statement. +func (n *CompoundStatement) IsJumpTarget() bool { return n.isJumpTarget } + +func (n *CompoundStatement) hasLabel() { + for ; n != nil; n = n.parent { + n.isJumpTarget = true + } +} + +// Declarations returns the list of declarations in n. +func (n *CompoundStatement) Declarations() []*Declaration { return n.declarations } + +// Children returns the list of n's children. +func (n *CompoundStatement) Children() []*CompoundStatement { return n.children } + +// CompoundStatements returns the list of compound statements in n. +func (n *FunctionDefinition) CompoundStatements() []*CompoundStatement { return n.compoundStatements } + +// CompoundStatement returns the block containing n. +func (n *LabeledStatement) CompoundStatement() *CompoundStatement { return n.block } + +// LabeledStatements returns labeled statements of n. +func (n *CompoundStatement) LabeledStatements() []*LabeledStatement { return n.labeledStmts } + +// HasInitializer reports whether d has an initializator. +func (n *Declarator) HasInitializer() bool { return n.hasInitializer } + +// Context reports the statement, if any, a break or continue belongs to. Valid +// only after typecheck and for n.Case == JumpStatementBreak or +// JumpStatementContinue. +func (n *JumpStatement) Context() Node { return n.context } + +// IsFunctionPrototype reports whether n is a function prototype. +func (n *Declarator) IsFunctionPrototype() bool { + return n != nil && n.Type() != nil && n.Type().Kind() == Function && !n.fnDef && !n.IsParameter +} + +// DeclarationSpecifiers returns the declaration specifiers associated with n or nil. +func (n *Declarator) DeclarationSpecifiers() *DeclarationSpecifiers { + if x, ok := n.td.(*DeclarationSpecifiers); ok { + return x + } + + return nil +} + +// SpecifierQualifierList returns the specifier qualifer list associated with n or nil. +func (n *Declarator) SpecifierQualifierList() *SpecifierQualifierList { + if x, ok := n.td.(*SpecifierQualifierList); ok { + return x + } + + return nil +} + +// TypeQualifier returns the type qualifiers associated with n or nil. +func (n *Declarator) TypeQualifiers() *TypeQualifiers { + if x, ok := n.td.(*TypeQualifiers); ok { + return x + } + + return nil +} + +// StructDeclaration returns the struct declaration associated with n. +func (n *StructDeclarator) StructDeclaration() *StructDeclaration { return n.decl } diff --git a/vendor/modernc.org/cc/v3/cc.go b/vendor/modernc.org/cc/v3/cc.go new file mode 100644 index 00000000..cc8e90c4 --- /dev/null +++ b/vendor/modernc.org/cc/v3/cc.go @@ -0,0 +1,972 @@ +// 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. + +//TODO https://todo.sr.ht/~mcf/cc-issues/34 +//TODO http://mcpp.sourceforge.net/ "Provides a validation suite to test C/C++ preprocessor's conformance and quality comprehensively." + +//go:generate rm -f lexer.go +//go:generate golex -o lexer.go lexer.l + +//go:generate rm -f ast.go +//go:generate yy -o /dev/null -position -astImport "\"fmt\"\n\n\"modernc.org/token\"" -prettyString PrettyString -kind Case -noListKind -noPrivateHelpers -forceOptPos parser.yy + +//go:generate stringer -output stringer.go -linecomment -type=Kind,Linkage + +//go:generate sh -c "go test -run ^Example |fe" + +// Package cc is a C99 compiler front end (Work in progress). +// +// Installation +// +// To install/update cc/v3 invoke: +// +// $ go get [-u] modernc.org/cc/v3 +// +// Online documentation +// +// See https://godoc.org/modernc.org/cc/v3. +// +// Status +// +// Most of the functionality is now working. +// +// Supported platforms +// +// The code is known to work on Darwin, Linux and Windows, but the supported +// features may vary. +// +// Links +// +// Referenced from elsewhere: +// +// [0]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf +// [1]: https://www.spinellis.gr/blog/20060626/cpp.algo.pdf +// [2]: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf +// [3]: http://gallium.inria.fr/~fpottier/publis/jourdan-fpottier-2016.pdf +// [4]: https://gcc.gnu.org/onlinedocs/gcc-8.3.0/gcc/Attribute-Syntax.html#Attribute-Syntax +package cc // import "modernc.org/cc/v3" + +import ( + "fmt" + goscanner "go/scanner" + gotoken "go/token" + "hash/maphash" + "io" + "math" + "os" + "os/exec" + "reflect" + "regexp" + "runtime" + "sort" + "strconv" + "strings" + "sync" + "sync/atomic" + + "modernc.org/strutil" + "modernc.org/token" +) + +const ( + scopeParent StringID = -iota - 1 + scopeSkip +) + +var ( + _ Pragma = (*pragma)(nil) + + cache = newPPCache() + dict = newDictionary() + dictStrings [math.MaxUint8 + 1]string + noPos token.Position + + debugIncludePaths bool + debugWorkingDir bool + isTesting bool + isTestingMingw bool + + idPtrdiffT = dict.sid("ptrdiff_t") + idSizeT = dict.sid("size_t") + idWCharT = dict.sid("wchar_t") + + token4Pool = sync.Pool{New: func() interface{} { r := make([]token4, 0); return &r }} //DONE benchmrk tuned capacity + tokenPool = sync.Pool{New: func() interface{} { r := make([]Token, 0); return &r }} //DONE benchmrk tuned capacity + + printHooks = strutil.PrettyPrintHooks{ + reflect.TypeOf(Token{}): func(f strutil.Formatter, v interface{}, prefix, suffix string) { + t := v.(Token) + if (t == Token{}) { + return + } + + f.Format(prefix) + r := t.Rune + if p := t.Position(); p.IsValid() { + f.Format("%v: ", p) + } + s := tokName(r) + if x := s[0]; x >= '0' && x <= '9' { + s = strconv.QuoteRune(r) + } + f.Format("%s", s) + if s := t.Value.String(); len(s) != 0 { + f.Format(" %q", s) + } + f.Format(suffix) + }, + reflect.TypeOf((*operand)(nil)): func(f strutil.Formatter, v interface{}, prefix, suffix string) { + op := v.(*operand) + f.Format(prefix) + f.Format("[%v %T(%[2]v)]", op.Type(), op.Value()) + f.Format(suffix) + }, + } +) + +func todo(s string, args ...interface{}) string { //TODO- + switch { + case s == "": + s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) + default: + s = fmt.Sprintf(s, args...) + } + pc, fn, fl, _ := runtime.Caller(1) + f := runtime.FuncForPC(pc) + var fns string + if f != nil { + fns = f.Name() + if x := strings.LastIndex(fns, "."); x > 0 { + fns = fns[x+1:] + } + } + r := fmt.Sprintf("%s:%d:%s: TODOTODO %s", fn, fl, fns, s) //TODOOK + fmt.Fprintf(os.Stdout, "%s\n", r) + os.Stdout.Sync() + return r +} + +func trc(s string, args ...interface{}) string { //TODO- + switch { + case s == "": + s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...) + default: + s = fmt.Sprintf(s, args...) + } + pc, fn, fl, _ := runtime.Caller(1) + f := runtime.FuncForPC(pc) + var fns string + if f != nil { + fns = f.Name() + if x := strings.LastIndex(fns, "."); x > 0 { + fns = fns[x+1:] + } + } + r := fmt.Sprintf("%s:%d:%s: TRC %s", fn, fl, fns, s) + fmt.Fprintf(os.Stdout, "%s\n", r) + os.Stdout.Sync() + return r +} + +func origin(skip int) string { + pc, fn, fl, _ := runtime.Caller(skip) + f := runtime.FuncForPC(pc) + var fns string + if f != nil { + fns = f.Name() + if x := strings.LastIndex(fns, "."); x > 0 { + fns = fns[x+1:] + } + } + return fmt.Sprintf("%s:%d:%s", fn, fl, fns) +} + +// String returns a StringID for a given value. +func String(s string) StringID { + return dict.sid(s) +} + +// Linkage represents identifier linkage. +// +// [0]6.2.2: An identifier declared in different scopes or in the same scope +// more than once can be made to refer to the same object or function by a +// process called linkage. There are three kinds of linkage: External, +// Internal, and None. +type Linkage int + +// StorageClass determines storage duration. +// +// [0]6.2.4: An object has a storage duration that determines its lifetime. +// There are three storage durations: Static, Automatic, and Allocated. +type StorageClass int + +// Pragma defines behavior of the object passed to Config.PragmaHandler. +type Pragma interface { + Error(msg string, args ...interface{}) // Report error. + MaxAligment() int // Returns the current maximum alignment. May return zero. + MaxInitialAligment() int // Support #pragma pack(). Returns the maximum alignment in effect at start. May return zero. + PopMacro(string) + PushMacro(string) + SetAlignment(n int) // Support #pragma pack(n) +} + +type pragma struct { + tok cppToken + c *cpp +} + +func (p *pragma) Error(msg string, args ...interface{}) { p.c.err(p.tok, msg, args...) } + +func (p *pragma) MaxAligment() int { return p.c.ctx.maxAlign } + +func (p *pragma) MaxInitialAligment() int { return p.c.ctx.maxAlign0 } + +func (p *pragma) SetAlignment(n int) { + if n <= 0 { + p.Error("%T.SetAlignment(%d): invalid argument", p, n) + return + } + + p.c.ctx.maxAlign = n +} + +func (p *pragma) PushMacro(nm string) { + id := dict.sid(nm) + if p.c.macroStack == nil { + p.c.macroStack = map[StringID][]*Macro{} + } + if m := p.c.macros[id]; m != nil { + p.c.macroStack[id] = append(p.c.macroStack[id], p.c.macros[id]) + } +} + +func (p *pragma) PopMacro(nm string) { + id := dict.sid(nm) + a := p.c.macroStack[id] + if n := len(a); n != 0 { + p.c.macros[id] = a[n-1] + p.c.macroStack[id] = a[:n-1] + } +} + +// PrettyString returns a formatted representation of things produced by this package. +func PrettyString(v interface{}) string { + return strutil.PrettyString(v, "", "", printHooks) +} + +// StringID is a process-unique string numeric identifier. Its zero value +// represents an empty string. +type StringID int32 + +// String implements fmt.Stringer. +func (n StringID) String() (r string) { + if n < 256 { + return dictStrings[byte(n)] + } + + dict.mu.RLock() + r = dict.strings[n] + dict.mu.RUnlock() + return r +} + +// Node is implemented by Token and all AST nodes. +type Node interface { + Position() token.Position +} + +type noder struct{} + +func (noder) Position() token.Position { panic(internalError()) } + +// Scope maps identifiers to definitions. +type Scope map[StringID][]Node + +func (s *Scope) new() (r Scope) { + if *s == nil { + *s = Scope{} + } + r = Scope{scopeParent: []Node{struct { + noder + Scope + }{Scope: *s}}} + return r +} + +func (s *Scope) declare(nm StringID, n Node) { + sc := *s + if sc == nil { + *s = map[StringID][]Node{nm: {n}} + // t := "" + // if x, ok := n.(*Declarator); ok && x.IsTypedefName { + // t = ", typedefname" + // } + // dbg("declared %s%s at %v in scope %p", nm, t, n.Position(), *s) + return + } + + switch x := n.(type) { + case *Declarator, *StructDeclarator, *LabeledStatement, *BlockItem: + // nop + case *StructOrUnionSpecifier, *EnumSpecifier, *Enumerator: + for { + if _, ok := sc[scopeSkip]; !ok { + break + } + + sc = sc.Parent() + } + default: + panic(todo("%T", x)) + } + + sc[nm] = append(sc[nm], n) + // t := "" + // if x, ok := n.(*Declarator); ok && x.IsTypedefName { + // t = ", typedefname" + // } + // dbg("declared %s%s at %v in scope %p", nm, t, n.Position(), sc) +} + +// Parent returns s's outer scope, if any. +func (s Scope) Parent() Scope { + if s == nil { + return nil + } + + if x, ok := s[scopeParent]; ok { + return x[0].(struct { + noder + Scope + }).Scope + } + + return nil +} + +func (s *Scope) typedef(nm StringID, tok Token) *Declarator { + seq := tok.seq + for s := *s; s != nil; s = s.Parent() { + for _, v := range s[nm] { + switch x := v.(type) { + case *Declarator: + if !x.isVisible(seq) { + continue + } + + if x.IsTypedefName { + return x + } + + return nil + case *Enumerator: + return nil + case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator: + // nop + default: + panic(internalError()) + } + } + } + return nil +} + +func (s *Scope) declarator(nm StringID, tok Token) *Declarator { + seq := tok.seq + for s := *s; s != nil; s = s.Parent() { + defs := s[nm] + for _, v := range defs { + switch x := v.(type) { + case *Declarator: + if !x.isVisible(seq) { + continue + } + + for _, v := range defs { + if x, ok := v.(*Declarator); ok { + t := x.Type() + if t != nil && t.Kind() == Function { + if x.fnDef { + return x + } + + continue + } + + if t != nil && !x.Type().IsIncomplete() { + return x + } + } + + } + return x + case *Enumerator: + return nil + case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator: + // nop + default: + panic(internalError()) + } + } + } + return nil +} + +func (s *Scope) enumerator(nm StringID, tok Token) *Enumerator { + seq := tok.seq + for s := *s; s != nil; s = s.Parent() { + for _, v := range s[nm] { + switch x := v.(type) { + case *Declarator: + if !x.isVisible(seq) { + continue + } + + return nil + case *Enumerator: + return x + case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator: + // nop + default: + panic(internalError()) + } + } + } + return nil +} + +// Config3 amends behavior of translation phases 1 to 3. +type Config3 struct { + // If IgnoreInclude is not nil, its MatchString method will be called by the + // preprocessor with the argument any include directive expands to. If the call + // evaluates to is true the include directive will be ignored completely. + IgnoreInclude *regexp.Regexp + + // Name of a macro to use instead of FD_ZERO. + // + // Note: Temporary solution will be removed/replaced + ReplaceMacroFdZero string + // Name of a macro to use instead of TCL_DEFAULT_DOUBLE_ROUNDING. + // + // Note: Temporary solution will be removed/replaced + ReplaceMacroTclDefaultDoubleRounding string // Name of a macro to use instead of TCL_DEFAULT_DOUBLE_ROUNDING. Note: Temporrary solution will be removed/replaced + // Name of a macro to use instead of TCL_IEEE_DOUBLE_ROUNDING. + // + // Note: Temporary solution will be removed/replaced + ReplaceMacroTclIeeeDoubleRounding string + + WorkingDir string // Overrides os.Getwd if non empty. + Filesystem Filesystem // Overrides filesystem access if not empty. + + MaxSourceLine int // Zero: Scanner will use default buffer. Non zero: Scanner will use max(default buffer size, MaxSourceLine). + + // DisableBuiltinResolution disables resolution of undefined identifiers such + // that eg. abort, becomes the same as __builtin_abort, prototype of which is + // expected to be provided by one of the sources passed to Parse, Preprocess or + // Translate. + DisableBuiltinResolution bool + + DisableTrigraphs bool // GCC ignores them unless -trigraphs is used: https://gcc.gnu.org/onlinedocs/cpp/Initial-processing.html + GCCStructs bool // Assume __attribute__(gcc_struct) applied to structs by default. + //TODO MSStructs bool // Assume __attribute__(ms_struct) applied to structs by default. + NoFieldAndBitfieldOverlap bool // Only bitfields can be grouped together. + PreserveOnlyLastNonBlankSeparator bool // If PreserveWhiteSpace is true, keep only the last white space, do not combine + PreserveWhiteSpace bool // Including also comments. + RejectElseExtraTokens bool // Pedantic: do not silently accept "#else foo". + RejectEndifExtraTokens bool // Pedantic: do not silently accept "#endif foo". + RejectFinalBackslash bool // Pedantic: do not silently accept "foo\\\n". + RejectFunctionMacroEmptyReplacementList bool // Pedantic: do not silently accept "#define foo(bar)\n". + RejectIfdefExtraTokens bool // Pedantic: do not silently accept "#ifdef foo bar". + RejectIfndefExtraTokens bool // Pedantic: do not silently accept "#ifndef foo bar". + RejectIncludeNext bool // Pedantic: do not silently accept "#include_next". + RejectInvalidVariadicMacros bool // Pedantic: do not silently accept "#define foo(bar...)". Standard allows only #define foo(bar, ...) + RejectLineExtraTokens bool // Pedantic: do not silently accept "#line 1234 \"foo.c\" bar". + RejectMissingFinalNewline bool // Pedantic: do not silently accept "foo\nbar". + RejectUndefExtraTokens bool // Pedantic: do not silently accept "#undef foo bar". + UnsignedEnums bool // GCC compatibility: enums with no negative values will have unsigned type. +} + +type SharedFunctionDefinitions struct { + M map[*FunctionDefinition]struct{} + m map[sharedFunctionDefinitionKey]*FunctionDefinition //TODO + hash maphash.Hash +} + +type sharedFunctionDefinitionKey struct { + pos StringID + nm StringID + hash uint64 +} + +// Config amends behavior of translation phase 4 and above. Instances of Config +// are not mutated by this package and it's safe to share/reuse them. +// +// The *Config passed to Parse or Translate should not be mutated afterwards. +type Config struct { + Config3 + ABI ABI + + PragmaHandler func(Pragma, []Token) // Called on pragmas, other than #pragma STDC ..., if non nil + + // SharedFunctionDefinitions collects function definitions having the same + // position and definition. This can happen, for example, when a function is + // defined in a header file included multiple times. Either within a single + // translation unit or across translation units. In the later case just supply + // the same SharedFunctionDefinitions in Config when translating/parsing each + // translation unit. + SharedFunctionDefinitions *SharedFunctionDefinitions + + // IncludeFileHandler, when non nil, is called by the preprocessor for every + // successfully included file. + IncludeFileHandler func(pos gotoken.Position, includePath string) + + MaxErrors int // 0: default (10), < 0: unlimited, n: n. + + CheckExternInlineFnBodies bool // Translate will consider extern inline function bodies. + DebugIncludePaths bool // Output to stderr. + DebugWorkingDir bool // Output to stderr. + DoNotTypecheckAsm bool + EnableAssignmentCompatibilityChecking bool // No such checks performed up to v3.31.0. Currently only partially implemented. + InjectTracingCode bool // Output to stderr. + LongDoubleIsDouble bool + PreprocessOnly bool + RejectAnonymousFields bool // Pedantic: do not silently accept "struct{int;}". + RejectCaseRange bool // Pedantic: do not silently accept "case 'a'...'z':". + RejectEmptyCompositeLiterals bool // Pedantic: do not silently accept "foo = (T){}". + RejectEmptyDeclarations bool // Pedantic: do not silently accept "int foo(){};". + RejectEmptyFields bool // Pedantic: do not silently accept "struct {int a;;} foo;". + RejectEmptyInitializerList bool // Pedantic: do not silently accept "foo f = {};". + RejectEmptyStructDeclaration bool // Pedantic: do not silently accept "struct{; int i}". + RejectEmptyStructs bool // Pedantic: do not silently accept "struct foo {};". + RejectIncompatibleMacroRedef bool // Pedantic: do not silently accept "#define MIN(A,B) ...\n#define MIN(a,b) ...\n" etc. + RejectLabelValues bool // Pedantic: do not silently accept "foo: bar(); void *ptr = &&foo;" or "goto *ptr". + RejectLateBinding bool // Pedantic: do not silently accept void f() { g(); } void g() {} + RejectMissingConditionalExpr bool // Pedantic: do not silently accept "foo = bar ? : baz;". + RejectMissingDeclarationSpecifiers bool // Pedantic: do not silently accept "main() {}". + RejectMissingFinalStructFieldSemicolon bool // Pedantic: do not silently accept "struct{int i; int j}". + RejectNestedFunctionDefinitions bool // Pedantic: do not silently accept nested function definitons. + RejectParamSemicolon bool // Pedantic: do not silently accept "int f(int a; int b)". + RejectStatementExpressions bool // Pedantic: do not silently accept "i = ({foo();})". + RejectTypeof bool // Pedantic: do not silently accept "typeof foo" or "typeof(bar*)". + RejectUninitializedDeclarators bool // Reject int f() { int j; return j; } + TrackAssignments bool // Collect a list of LHS declarators a declarator is used in RHS or as an function argument. + doNotSanityCheckComplexTypes bool // Testing only + fakeIncludes bool // Testing only. + ignoreErrors bool // Testing only. + ignoreIncludes bool // Testing only. + ignoreUndefinedIdentifiers bool // Testing only. +} + +type context struct { + ast *AST + breakCtx Node + breaks int + casePromote Type + cases []*LabeledStatement // switch + cfg *Config + checkFn *FunctionDefinition + closure map[StringID]struct{} + continues int + enums map[StringID]Operand //TODO putting this in alphabetical order within the struct causes crashes in VirtualBox/386 ??? + goscanner.ErrorList + includePaths []string + intBits int + intMaxWidth int64 // Set if the preprocessor saw __INTMAX_WIDTH__. + keywords map[StringID]rune + maxAlign int // If non zero: maximum alignment of members of structures (other than zero-width bitfields). + maxAlign0 int + maxErrors int + mode mode + modes []mode + mu sync.Mutex + ptrdiffT Type + readDelta int + sizeT Type + structTypes map[StringID]Type + structs map[StructInfo]struct{} + switches int + sysIncludePaths []string + tuSize0 int64 // Sum of sizes of processed inputs + tuSources0 int32 // Number of processed inputs + wcharT Type + + capture bool + evalIdentError bool +} + +func newContext(cfg *Config) *context { + maxErrors := cfg.MaxErrors + if maxErrors == 0 { + maxErrors = 10 + } + return &context{ + cfg: cfg, + enums: map[StringID]Operand{}, + keywords: keywords, + maxErrors: maxErrors, + structTypes: map[StringID]Type{}, + structs: map[StructInfo]struct{}{}, + } +} + +func (c *context) tuSizeAdd(n int64) { atomic.AddInt64(&c.tuSize0, n) } +func (c *context) tuSize() int64 { return atomic.LoadInt64(&c.tuSize0) } +func (c *context) tuSourcesAdd(n int32) { atomic.AddInt32(&c.tuSources0, n) } +func (c *context) tuSources() int { return int(atomic.LoadInt32(&c.tuSources0)) } + +func (c *context) stddef(nm StringID, s Scope, tok Token) Type { + if d := s.typedef(nm, tok); d != nil { + if t := d.Type(); t != nil && t.Kind() != Invalid { + return t + } + } + + c.errNode(&tok, "front-end: undefined: %s", nm) + return noType +} + +func (c *context) assignmentCompatibilityErrorCond(n Node, a, b Type) (stop bool) { + if !c.cfg.EnableAssignmentCompatibilityChecking { + return + } + + return c.errNode(n, "invalid type combination of conditional operator: %v and %v", a, b) +} + +func (c *context) assignmentCompatibilityError(n Node, lhs, rhs Type) (stop bool) { + if !c.cfg.EnableAssignmentCompatibilityChecking { + return + } + + return c.errNode(n, "cannot use %v as type %v in assignment", rhs, lhs) +} + +func (c *context) errNode(n Node, msg string, args ...interface{}) (stop bool) { + return c.err(n.Position(), msg, args...) +} + +func (c *context) err(pos token.Position, msg string, args ...interface{}) (stop bool) { + // dbg("FAIL "+msg, args...) + //fmt.Printf("FAIL "+msg+"\n", args...) + if c.cfg.ignoreErrors { + return false + } + + s := fmt.Sprintf(msg, args...) + c.mu.Lock() + max := c.maxErrors + switch { + case max < 0 || max > len(c.ErrorList): + c.ErrorList.Add(gotoken.Position(pos), s) + default: + stop = true + } + c.mu.Unlock() + return stop +} + +func (c *context) errs(list goscanner.ErrorList) (stop bool) { + c.mu.Lock() + + defer c.mu.Unlock() + + max := c.maxErrors + for _, v := range list { + switch { + case max < 0 || max > len(c.ErrorList): + c.ErrorList = append(c.ErrorList, v) + default: + return true + } + } + return false +} + +func (c *context) Err() error { + c.mu.Lock() + switch x := c.ErrorList.Err().(type) { + case goscanner.ErrorList: + x = append(goscanner.ErrorList(nil), x...) + c.mu.Unlock() + var lpos gotoken.Position + w := 0 + for _, v := range x { + if lpos.Filename != "" { + if v.Pos.Filename == lpos.Filename && v.Pos.Line == lpos.Line { + continue + } + } + + x[w] = v + w++ + lpos = v.Pos + } + x = x[:w] + sort.Slice(x, func(i, j int) bool { + a := x[i] + b := x[j] + if !a.Pos.IsValid() && b.Pos.IsValid() { + return true + } + + if a.Pos.IsValid() && !b.Pos.IsValid() { + return false + } + + if a.Pos.Filename < b.Pos.Filename { + return true + } + + if a.Pos.Filename > b.Pos.Filename { + return false + } + + if a.Pos.Line < b.Pos.Line { + return true + } + + if a.Pos.Line > b.Pos.Line { + return false + } + + return a.Pos.Column < b.Pos.Column + }) + a := make([]string, 0, len(x)) + for _, v := range x { + a = append(a, v.Error()) + } + return fmt.Errorf("%s", strings.Join(a, "\n")) + default: + c.mu.Unlock() + return x + } +} + +func (c *context) not(n Node, mode mode) { + if c.mode&mode != 0 { + switch mode { + case mIntConstExpr: + c.errNode(n, "invalid integer constant expression") + default: + panic(internalError()) + } + } +} + +func (c *context) push(mode mode) { + c.modes = append(c.modes, c.mode) + c.mode = mode +} + +func (c *context) pop() { + n := len(c.modes) + c.mode = c.modes[n-1] + c.modes = c.modes[:n-1] +} + +func (c *context) statFile(name string, sys bool) (os.FileInfo, error) { + fs := c.cfg.Config3.Filesystem + if fs == nil { + fs = LocalFS() + } + return fs.Stat(name, sys) +} + +func (c *context) openFile(name string, sys bool) (io.ReadCloser, error) { + fs := c.cfg.Config3.Filesystem + if fs == nil { + fs = LocalFS() + } + return fs.Open(name, sys) +} + +// HostConfig returns the system C preprocessor/compiler configuration, or an +// error, if any. The configuration is obtained by running the command named +// by the cpp argumnent or "cpp" when it's empty. For the predefined macros +// list the '-dM' options is added. For the include paths lists, the option +// '-v' is added and the output is parsed to extract the "..." include and +// <...> include paths. To add any other options to cpp, list them in opts. +// +// The function relies on a POSIX/GCC compatible C preprocessor installed. +// Execution of HostConfig is not free, so caching of the results is +// recommended. +func HostConfig(cpp string, opts ...string) (predefined string, includePaths, sysIncludePaths []string, err error) { + if cpp == "" { + cpp = "cpp" + } + args := append(append([]string{"-dM"}, opts...), os.DevNull) + pre, err := exec.Command(cpp, args...).Output() + if err != nil { + return "", nil, nil, err + } + + args = append(append([]string{"-v"}, opts...), os.DevNull) + out, err := exec.Command(cpp, args...).CombinedOutput() + if err != nil { + return "", nil, nil, err + } + + sep := "\n" + if env("GOOS", runtime.GOOS) == "windows" { + sep = "\r\n" + } + + a := strings.Split(string(out), sep) + for i := 0; i < len(a); { + switch a[i] { + case "#include \"...\" search starts here:": + loop: + for i = i + 1; i < len(a); { + switch v := a[i]; { + case strings.HasPrefix(v, "#") || v == "End of search list.": + break loop + default: + includePaths = append(includePaths, strings.TrimSpace(v)) + i++ + } + } + case "#include <...> search starts here:": + for i = i + 1; i < len(a); { + switch v := a[i]; { + case strings.HasPrefix(v, "#") || v == "End of search list.": + return string(pre), includePaths, sysIncludePaths, nil + default: + sysIncludePaths = append(sysIncludePaths, strings.TrimSpace(v)) + i++ + } + } + default: + i++ + } + } + return "", nil, nil, fmt.Errorf("failed parsing %s -v output", cpp) +} + +func env(key, val string) string { + if s := os.Getenv(key); s != "" { + return s + } + + return val +} + +// Token is a grammar terminal. +type Token struct { + Rune rune // ';' or IDENTIFIER etc. + Sep StringID // If Config3.PreserveWhiteSpace is in effect: All preceding white space combined, including comments. + Value StringID // ";" or "foo" etc. + Src StringID + file *tokenFile + macro StringID + pos int32 + seq int32 +} + +// Seq returns t's sequential number. +// +// Comparing positions as in 'before', 'after' is complicated as tokens in a +// translation unit usually come from more than one source file. Macro +// expansion further complicates that. The solution is sequentially numbering +// the tokens as they are finally seen by the parser, so the usual arithmetic +// '<', '>' operators can be used for that purpose. +func (t Token) Seq() int { return int(t.seq) } + +// Macro returns the name of a macro that expanded to this token, if any. +func (t *Token) Macro() StringID { return t.macro } + +// String implements fmt.Stringer. +func (t Token) String() string { return t.Value.String() } + +// Position implements Node. +func (t *Token) Position() (r token.Position) { + if t.pos != 0 && t.file != nil { + r = t.file.PositionFor(token.Pos(t.pos), true) + } + return r +} + +func tokStr(toks interface{}, sep string) string { + var b strings.Builder + switch x := toks.(type) { + case []token3: + for i, v := range x { + if i != 0 { + b.WriteString(sep) + } + b.WriteString(v.String()) + } + case []token4: + for i, v := range x { + if i != 0 { + b.WriteString(sep) + } + b.WriteString(v.String()) + } + case []cppToken: + for i, v := range x { + if i != 0 { + b.WriteString(sep) + } + b.WriteString(v.String()) + } + case []Token: + for i, v := range x { + if i != 0 { + b.WriteString(sep) + } + b.WriteString(v.String()) + } + default: + panic(internalError()) + } + return b.String() +} + +func internalError() int { + panic(fmt.Errorf("%v: internal error", origin(2))) +} + +func internalErrorf(s string, args ...interface{}) int { + s = fmt.Sprintf(s, args) + panic(fmt.Errorf("%v: %s", origin(2), s)) +} + +func detectMingw(s string) bool { + return strings.Contains(s, "#define __MINGW") +} + +func nodeSource(n ...Node) (r string) { + if len(n) == 0 { + return "" + } + + var a []*Token + for _, v := range n { + Inspect(v, func(n Node, _ bool) bool { + if x, ok := n.(*Token); ok && x.Seq() != 0 { + a = append(a, x) + } + return true + }) + } + sort.Slice(a, func(i, j int) bool { + return a[i].Seq() < a[j].Seq() + }) + w := 0 + seq := -1 + for _, v := range a { + if n := v.Seq(); n != seq { + seq = n + a[w] = v + w++ + } + } + a = a[:w] + var b strings.Builder + for _, v := range a { + b.WriteString(v.Sep.String()) + b.WriteString(v.Src.String()) + } + return b.String() +} diff --git a/vendor/modernc.org/cc/v3/check.go b/vendor/modernc.org/cc/v3/check.go new file mode 100644 index 00000000..50887870 --- /dev/null +++ b/vendor/modernc.org/cc/v3/check.go @@ -0,0 +1,5268 @@ +// 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("<nil>") + 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("")) + } +} diff --git a/vendor/modernc.org/cc/v3/cpp.go b/vendor/modernc.org/cc/v3/cpp.go new file mode 100644 index 00000000..db4cee0f --- /dev/null +++ b/vendor/modernc.org/cc/v3/cpp.go @@ -0,0 +1,3101 @@ +// 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 ( + "bytes" + "fmt" + gotoken "go/token" + "math" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "time" + "unicode/utf8" + + "modernc.org/token" +) + +const ( + maxIncludeLevel = 200 // gcc, std is at least 15. +) + +var ( + _ tokenReader = (*cpp)(nil) + _ tokenWriter = (*cpp)(nil) + + idCOUNTER = dict.sid("__COUNTER__") + idCxLimitedRange = dict.sid("CX_LIMITED_RANGE") + idDATE = dict.sid("__DATE__") + idDefault = dict.sid("DEFAULT") + idDefined = dict.sid("defined") + idEmptyString = dict.sid(`""`) + idFILE = dict.sid("__FILE__") + idFPContract = dict.sid("FP_CONTRACT") + idFdZero = dict.sid("FD_ZERO") + idFenvAccess = dict.sid("FENV_ACCESS") + idGNUC = dict.sid("__GNUC__") + idHasIncludeImpl = dict.sid("__has_include_impl") + idIntMaxWidth = dict.sid("__INTMAX_WIDTH__") + idL = dict.sid("L") + idLINE = dict.sid("__LINE__") + idNL = dict.sid("\n") + idOff = dict.sid("OFF") + idOn = dict.sid("ON") + idOne = dict.sid("1") + idPragmaSTDC = dict.sid("__pragma_stdc") + idSTDC = dict.sid("STDC") + idTIME = dict.sid("__TIME__") + idTclDefaultDoubleRounding = dict.sid("TCL_DEFAULT_DOUBLE_ROUNDING") + idTclIeeeDoubleRounding = dict.sid("TCL_IEEE_DOUBLE_ROUNDING") + idVaArgs = dict.sid("__VA_ARGS__") + idZero = dict.sid("0") + + cppTokensPool = sync.Pool{New: func() interface{} { r := []cppToken{}; return &r }} + + protectedMacros = hideSet{ // [0], 6.10.8, 4 + dict.sid("__STDC_HOSTED__"): {}, + dict.sid("__STDC_IEC_559_COMPLEX__"): {}, + dict.sid("__STDC_IEC_559__"): {}, + dict.sid("__STDC_ISO_10646__"): {}, + dict.sid("__STDC_MB_MIGHT_NEQ_WC__"): {}, + dict.sid("__STDC_VERSION__"): {}, + dict.sid("__STDC__"): {}, + idCOUNTER: {}, + idDATE: {}, + idFILE: {}, + idLINE: {}, + idTIME: {}, + } +) + +type tokenReader interface { + read() (cppToken, bool) + unget(cppToken) + ungets([]cppToken) +} + +type tokenWriter interface { + write(cppToken) + writes([]cppToken) +} + +// token4 is produced by translation phase 4. +type token4 struct { + file *tokenFile //TODO sort fields + token3 +} + +func (t *token4) Position() (r token.Position) { + if t.pos != 0 && t.file != nil { + r = t.file.PositionFor(token.Pos(t.pos), true) + } + return r +} + +type hideSet map[StringID]struct{} + +type cppToken struct { + token4 + hs hideSet +} + +func (t *cppToken) has(nm StringID) bool { _, ok := t.hs[nm]; return ok } + +type cppWriter struct { + toks []cppToken +} + +func (w *cppWriter) write(tok cppToken) { w.toks = append(w.toks, tok) } +func (w *cppWriter) writes(toks []cppToken) { w.toks = append(w.toks, toks...) } + +type ungetBuf []cppToken + +func (u *ungetBuf) unget(t cppToken) { *u = append(*u, t) } + +func (u *ungetBuf) read() (t cppToken) { + s := *u + n := len(s) - 1 + t = s[n] + *u = s[:n] + return t +} +func (u *ungetBuf) ungets(toks []cppToken) { + s := *u + for i := len(toks) - 1; i >= 0; i-- { + s = append(s, toks[i]) + } + *u = s +} + +func cppToksStr(toks []cppToken, sep string) string { + var b strings.Builder + for i, v := range toks { + if i != 0 { + b.WriteString(sep) + } + b.WriteString(v.String()) + } + return b.String() +} + +func cppToksStr2(toks [][]cppToken) string { + panic(todo("")) + var a []string + for _, v := range toks { + a = append(a, fmt.Sprintf("%q", cppToksStr(v, "|"))) + } + return fmt.Sprint(a) +} + +type cppReader struct { + buf []cppToken + ungetBuf +} + +func (r *cppReader) read() (tok cppToken, ok bool) { + if len(r.ungetBuf) != 0 { + return r.ungetBuf.read(), true + } + + if len(r.buf) == 0 { + return tok, false + } + + tok = r.buf[0] + r.buf = r.buf[1:] + return tok, true +} + +type cppScanner []cppToken + +func (s *cppScanner) peek() (r cppToken) { + r.char = -1 + if len(*s) == 0 { + return r + } + + return (*s)[0] +} + +func (s *cppScanner) next() (r cppToken) { + r.char = -1 + if len(*s) == 0 { + return r + } + + *s = (*s)[1:] + return s.peek() +} + +func (s *cppScanner) Pos() token.Pos { + if len(*s) == 0 { + return 0 + } + + return (*s)[0].Pos() +} + +// Macro represents a preprocessor macro definition. +type Macro struct { + fp []StringID + repl []token3 + repl2 []Token + + name token4 + pos int32 + + isFnLike bool + namedVariadic bool // foo..., note no comma before ellipsis. + variadic bool +} + +// Position reports the position of the macro definition. +func (m *Macro) Position() token.Position { + if m.pos != 0 && m.name.file != nil { + return m.name.file.PositionFor(token.Pos(m.pos), true) + } + return token.Position{} +} + +// Parameters return the list of function-like macro parameters. +func (m *Macro) Parameters() []StringID { return m.fp } + +// ReplacementTokens return the list of tokens m is replaced with. Tokens in +// the returned list have only the Rune and Value fields valid. +func (m *Macro) ReplacementTokens() []Token { + if m.repl2 != nil { + return m.repl2 + } + + m.repl2 = make([]Token, len(m.repl)) + for i, v := range m.repl { + m.repl2[i] = Token{Rune: v.char, Value: v.value, Src: v.src} + } + return m.repl2 +} + +// IsFnLike reports whether m is a function-like macro. +func (m *Macro) IsFnLike() bool { return m.isFnLike } + +func (m *Macro) isNamedVariadicParam(nm StringID) bool { + return m.namedVariadic && nm == m.fp[len(m.fp)-1] +} + +func (m *Macro) param2(varArgs []cppToken, ap [][]cppToken, nm StringID, out *[]cppToken, argIndex *int) bool { + *out = nil + if nm == idVaArgs || m.isNamedVariadicParam(nm) { + if !m.variadic { + return false + } + + *out = append([]cppToken(nil), varArgs...) + return true + } + + for i, v := range m.fp { + if v == nm { + if i < len(ap) { + a := ap[i] + for len(a) != 0 && a[0].char == ' ' { + a = a[1:] + } + *out = a + } + if argIndex != nil { + *argIndex = i + } + return true + } + } + return false +} + +func (m *Macro) param(varArgs []cppToken, ap [][]cppToken, nm StringID, out *[]cppToken) bool { + // trc("select (A) varArgs %q, ap %v, nm %q, out %q", cppToksStr(varArgs, "|"), cppToksStr2(ap), nm, cppToksStr(*out, "|")) + // defer func() { + // trc("select (A) varArgs %q, ap %v, nm %q, out %q", cppToksStr(varArgs, "|"), cppToksStr2(ap), nm, cppToksStr(*out, "|")) + // }() + return m.param2(varArgs, ap, nm, out, nil) +} + +// --------------------------------------------------------------- Preprocessor + +type cpp struct { + counter int + counterMacro Macro + ctx *context + dateMacro Macro + file *tokenFile + fileMacro Macro + in chan []token3 + inBuf []token3 + includeLevel int + lineMacro Macro + macroStack map[StringID][]*Macro + macros map[StringID]*Macro + out chan *[]token4 + outBuf *[]token4 + pragmaOpBuf []token4 + rq chan struct{} + timeMacro Macro + ungetBuf + + last rune + + intmaxChecked bool + nonFirstRead bool + seenEOF bool + inPragmaOp bool +} + +func newCPP(ctx *context) *cpp { + b := token4Pool.Get().(*[]token4) + *b = (*b)[:0] + r := &cpp{ + ctx: ctx, + macroStack: map[StringID][]*Macro{}, + macros: map[StringID]*Macro{}, + outBuf: b, + } + r.counterMacro = Macro{repl: []token3{{char: PPNUMBER}}} + r.dateMacro = Macro{repl: []token3{{char: STRINGLITERAL}}} + r.timeMacro = Macro{repl: []token3{{char: STRINGLITERAL}}} + r.fileMacro = Macro{repl: []token3{{char: STRINGLITERAL}}} + r.lineMacro = Macro{repl: []token3{{char: PPNUMBER}}} + r.macros = map[StringID]*Macro{ + idCOUNTER: &r.counterMacro, + idDATE: &r.dateMacro, + idFILE: &r.fileMacro, + idLINE: &r.lineMacro, + idTIME: &r.timeMacro, + } + t := time.Now() + // This macro expands to a string constant that describes the date on which the + // preprocessor is being run. The string constant contains eleven characters + // and looks like "Feb 12 1996". If the day of the month is less than 10, it is + // padded with a space on the left. + r.dateMacro.repl[0].value = dict.sid(t.Format("\"Jan _2 2006\"")) + // This macro expands to a string constant that describes the time at which the + // preprocessor is being run. The string constant contains eight characters and + // looks like "23:59:01". + r.timeMacro.repl[0].value = dict.sid(t.Format("\"15:04:05\"")) + return r +} + +func (c *cpp) cppToks(toks []token3) (r []cppToken) { + r = make([]cppToken, len(toks)) + for i, v := range toks { + r[i].token4.token3 = v + r[i].token4.file = c.file + } + return r +} + +func (c *cpp) err(n node, msg string, args ...interface{}) (stop bool) { + var position token.Position + switch x := n.(type) { + case nil: + case token4: + position = x.Position() + default: + if p := n.Pos(); p.IsValid() { + position = c.file.PositionFor(p, true) + } + } + return c.ctx.err(position, msg, args...) +} + +func (c *cpp) read() (cppToken, bool) { + if len(c.ungetBuf) != 0 { + return c.ungetBuf.read(), true + } + + if len(c.inBuf) == 0 { + if c.seenEOF { + return cppToken{}, false + } + + if c.nonFirstRead { + c.rq <- struct{}{} + } + c.nonFirstRead = true + + var ok bool + if c.inBuf, ok = <-c.in; !ok { + c.seenEOF = true + return cppToken{}, false + } + } + + tok := c.inBuf[0] + c.inBuf = c.inBuf[1:] + return cppToken{token4{token3: tok, file: c.file}, nil}, true +} + +func (c *cpp) write(tok cppToken) { + if tok.char == ' ' && c.last == ' ' { + return + } + + if c.ctx.cfg.PreprocessOnly { + switch { + case + //TODO cover ALL the bad combinations + c.last == '+' && tok.char == '+', + c.last == '+' && tok.char == INC, + c.last == '-' && tok.char == '-', + c.last == '-' && tok.char == DEC, + c.last == IDENTIFIER && tok.char == IDENTIFIER, + c.last == PPNUMBER && tok.char == '+', //TODO not when ends in a digit + c.last == PPNUMBER && tok.char == '-': //TODO not when ends in a digit + + sp := tok + sp.char = ' ' + sp.value = idSpace + *c.outBuf = append(*c.outBuf, sp.token4) + } + } + + //dbg("%T.write %q", c, tok) + c.last = tok.char + switch { + case c.inPragmaOp: + out: + switch tok.char { + case ')': + c.inPragmaOp = false + b := c.pragmaOpBuf + if len(b) == 0 || b[0].char != '(' { + c.err(b[0], "expected (") + break + } + + var a []string + for _, v := range b[1:] { + if v.char != STRINGLITERAL { + c.err(v, "expected string literal") + break out + } + + a = append(a, v.String()) + } + + if len(a) == 0 { + break + } + + for i, v := range a { + // [0], 6.10.9, 1 + if v[0] == 'L' { + v = v[1:] + } + v = v[1 : len(v)-1] + v = strings.ReplaceAll(v, `\"`, `"`) + a[i] = "#pragma " + strings.ReplaceAll(v, `\\`, `\`) + "\n" + } + src := strings.Join(a, "") + s := newScanner0(c.ctx, strings.NewReader(src), tokenNewFile("", len(src)), 4096) + if ppf := s.translationPhase3(); ppf != nil { + ppf.translationPhase4(c) + } + default: + c.pragmaOpBuf = append(c.pragmaOpBuf, tok.token4) + } + default: + switch { + case tok.char == '\n': + *c.outBuf = append(*c.outBuf, tok.token4) + c.out <- c.outBuf + b := token4Pool.Get().(*[]token4) + *b = (*b)[:0] + c.outBuf = b + case tok.char == IDENTIFIER && tok.value == idPragmaOp: + if len(*c.outBuf) != 0 { + tok.char = '\n' + tok.value = 0 + *c.outBuf = append(*c.outBuf, tok.token4) + c.out <- c.outBuf + b := token4Pool.Get().(*[]token4) + *b = (*b)[:0] + c.outBuf = b + } + c.inPragmaOp = true + c.pragmaOpBuf = c.pragmaOpBuf[:0] + default: + *c.outBuf = append(*c.outBuf, tok.token4) + } + } +} + +func ltrim4(toks []token4) []token4 { + for len(toks) != 0 && toks[0].char == ' ' { + toks = toks[1:] + } + return toks +} + +func (c *cpp) writes(toks []cppToken) { + for _, v := range toks { + c.write(v) + } +} + +// [1]pg 1. +// +// expand(TS) /* recur, substitute, pushback, rescan */ +// { +// if TS is {} then +// // ---------------------------------------------------------- A +// return {}; +// +// else if TS is T^HS • TS’ and T is in HS then +// //----------------------------------------------------------- B +// return T^HS • expand(TS’); +// +// else if TS is T^HS • TS’ and T is a "()-less macro" then +// // ---------------------------------------------------------- C +// return expand(subst(ts(T), {}, {}, HS \cup {T}, {}) • TS’ ); +// +// else if TS is T^HS •(•TS’ and T is a "()’d macro" then +// // ---------------------------------------------------------- D +// check TS’ is actuals • )^HS’ • TS’’ and actuals are "correct for T" +// return expand(subst(ts(T), fp(T), actuals,(HS \cap HS’) \cup {T }, {}) • TS’’); +// +// // ------------------------------------------------------------------ E +// note TS must be T^HS • TS’ +// return T^HS • expand(TS’); +// } +func (c *cpp) expand(ts tokenReader, w tokenWriter, expandDefined bool) { + // trc("==== expand enter") +start: + tok, ok := ts.read() + tok.file = c.file + // First, if TS is the empty set, the result is the empty set. + if !ok { + // ---------------------------------------------------------- A + // return {}; + // trc("---- expand A") + return + } + + // dbg("expand start %q", tok) + if tok.char == IDENTIFIER { + nm := tok.value + if nm == idDefined && expandDefined { + c.parseDefined(tok, ts, w) + goto start + } + + // Otherwise, if the token sequence begins with a token whose + // hide set contains that token, then the result is the token + // sequence beginning with that token (including its hide set) + // followed by the result of expand on the rest of the token + // sequence. + if tok.has(nm) { + // -------------------------------------------------- B + // return T^HS • expand(TS’); + // trc("---- expand B") + // trc("expand write %q", tok) + w.write(tok) + goto start + } + + m := c.macros[nm] + if m != nil && !m.isFnLike { + // Otherwise, if the token sequence begins with an + // object-like macro, the result is the expansion of + // the rest of the token sequence beginning with the + // sequence returned by subst invoked with the + // replacement token sequence for the macro, two empty + // sets, the union of the macro’s hide set and the + // macro itself, and an empty set. + switch nm { + case idLINE: + c.lineMacro.repl[0].value = dict.sid(fmt.Sprint(tok.Position().Line)) + case idCOUNTER: + c.counterMacro.repl[0].value = dict.sid(fmt.Sprint(c.counter)) + c.counter++ + case idTclDefaultDoubleRounding: + if c.ctx.cfg.ReplaceMacroTclDefaultDoubleRounding != "" { + m = c.macros[dict.sid(c.ctx.cfg.ReplaceMacroTclDefaultDoubleRounding)] + } + case idTclIeeeDoubleRounding: + if c.ctx.cfg.ReplaceMacroTclIeeeDoubleRounding != "" { + m = c.macros[dict.sid(c.ctx.cfg.ReplaceMacroTclIeeeDoubleRounding)] + } + } + if m != nil { + // -------------------------------------------------- C + // return expand(subst(ts(T), {}, {}, HS \cup {T}, {}) • TS’ ); + // trc("---- expand C") + hs := hideSet{nm: {}} + for k, v := range tok.hs { + hs[k] = v + } + os := cppTokensPool.Get().(*[]cppToken) + toks := c.subst(m, c.cppToks(m.repl), nil, nil, nil, hs, os, expandDefined) + for i := range toks { + toks[i].pos = tok.pos + } + if len(toks) == 1 { + toks[0].macro = nm + } + ts.ungets(toks) + (*os) = (*os)[:0] + cppTokensPool.Put(os) + goto start + } + } + + if m != nil && m.isFnLike { + switch nm { + case idFdZero: + if c.ctx.cfg.ReplaceMacroFdZero != "" { + m = c.macros[dict.sid(c.ctx.cfg.ReplaceMacroFdZero)] + } + } + if m != nil { + // -------------------------------------------------- D + // check TS’ is actuals • )^HS’ • TS’’ and actuals are "correct for T" + // return expand(subst(ts(T), fp(T), actuals,(HS \cap HS’) \cup {T }, {}) • TS’’); + // trc("---- expand D") + hs := tok.hs + var skip []cppToken + again: + t2, ok := ts.read() + if !ok { + // dbg("expand write %q", tok) + w.write(tok) + ts.ungets(skip) + goto start + } + + skip = append(skip, t2) + switch t2.char { + case '\n', ' ': + goto again + case '(': + // ok + default: + w.write(tok) + ts.ungets(skip) + goto start + } + + varArgs, ap, hs2 := c.actuals(m, ts) + if nm == idHasIncludeImpl { //TODO- + if len(ap) != 1 || len(ap[0]) != 1 { + panic(todo("internal error")) + } + + arg := ap[0][0].value.String() + switch { + case strings.HasPrefix(arg, `"\"`): // `"\"stdio.h\""` + arg = arg[2:len(arg)-3] + `"` // -> `"stdio.h"` + case strings.HasPrefix(arg, `"<`): // `"<stdio.h>"` + arg = arg[1 : len(arg)-1] // -> `<stdio.h>` + default: + arg = "" + } + var tok3 token3 + tok3.char = PPNUMBER + tok3.value = idZero + if arg != "" { + if _, err := c.hasInclude(&tok, arg); err == nil { + tok3.value = idOne + } + } + tok := cppToken{token4{token3: tok3, file: c.file}, nil} + ts.ungets([]cppToken{tok}) + goto start + } + + switch { + case len(hs2) == 0: + hs2 = hideSet{nm: {}} + default: + nhs := hideSet{} + for k := range hs { + if _, ok := hs2[k]; ok { + nhs[k] = struct{}{} + } + } + nhs[nm] = struct{}{} + hs2 = nhs + } + os := cppTokensPool.Get().(*[]cppToken) + toks := c.subst(m, c.cppToks(m.repl), m.fp, varArgs, ap, hs2, os, expandDefined) + for i := range toks { + toks[i].pos = tok.pos + } + ts.ungets(toks) + (*os) = (*os)[:0] + cppTokensPool.Put(os) + goto start + } + } + } + + // ------------------------------------------------------------------ E + // note TS must be T^HS • TS’ + // return T^HS • expand(TS’); + // trc("---- expand E") + // trc("expand write %q", tok) + w.write(tok) + goto start +} + +func (c *cpp) hasInclude(n Node, nm string) (rs string, err error) { + // nm0 := nm + // defer func() { //TODO- + // trc("nm0 %q nm %q rs %q err %v", nm0, nm, rs, err) + // }() + var ( + b byte + paths []string + sys bool + ) + switch { + case nm != "" && nm[0] == '"': + paths = c.ctx.includePaths + b = '"' + case nm != "" && nm[0] == '<': + paths = c.ctx.sysIncludePaths + sys = true + b = '>' + case nm == "": + return "", fmt.Errorf("%v: invalid empty include argument", n.Position()) + default: + return "", fmt.Errorf("%v: invalid include argument %s", n.Position(), nm) + } + + x := strings.IndexByte(nm[1:], b) + if x < 0 { + return "", fmt.Errorf("%v: invalid include argument %s", n.Position(), nm) + } + + nm = filepath.FromSlash(nm[1 : x+1]) + switch { + case filepath.IsAbs(nm): + fi, err := c.ctx.statFile(nm, sys) + if err != nil { + return "", fmt.Errorf("%v: %s", n.Position(), err) + } + + if fi.IsDir() { + return "", fmt.Errorf("%v: %s is a directory, not a file", n.Position(), nm) + } + + return nm, nil + default: + dir := filepath.Dir(c.file.Name()) + for _, v := range paths { + if v == "@" { + v = dir + } + + var p string + switch { + case strings.HasPrefix(nm, "./"): + wd := c.ctx.cfg.WorkingDir + if wd == "" { + var err error + if wd, err = os.Getwd(); err != nil { + return "", fmt.Errorf("%v: cannot determine working dir: %v", n.Position(), err) + } + } + p = filepath.Join(wd, nm) + default: + p = filepath.Join(v, nm) + } + fi, err := c.ctx.statFile(p, sys) + if err != nil || fi.IsDir() { + continue + } + + return p, nil + } + wd, _ := os.Getwd() + return "", fmt.Errorf("include file not found: %s (wd %s)\nsearch paths:\n\t%s", nm, wd, strings.Join(paths, "\n\t")) + } +} + +func (c *cpp) actuals(m *Macro, r tokenReader) (varArgs []cppToken, ap [][]cppToken, hs hideSet) { + var lvl, n int + varx := len(m.fp) + if m.namedVariadic { + varx-- + } + var last rune + for { + t, ok := r.read() + if !ok { + c.err(t, "unexpected EOF") + return nil, nil, nil + } + + // 6.10.3, 10 + // + // Within the sequence of preprocessing tokens making up an + // invocation of a function-like macro, new-line is considered + // a normal white-space character. + if t.char == '\n' { + t.char = ' ' + t.value = idSpace + } + if t.char == ' ' && last == ' ' { + continue + } + + last = t.char + switch t.char { + case ',': + if lvl == 0 { + if n >= varx && (len(varArgs) != 0 || !isWhite(t.char)) { + varArgs = append(varArgs, t) + } + n++ + continue + } + case ')': + if lvl == 0 { + for len(ap) < len(m.fp) { + ap = append(ap, nil) + } + for i, v := range ap { + ap[i] = c.trim(v) + } + // for i, v := range ap { + // dbg("%T.actuals %v/%v %q", c, i, len(ap), tokStr(v, "|")) + // } + return c.trim(varArgs), ap, t.hs + } + lvl-- + case '(': + lvl++ + } + if n >= varx && (len(varArgs) != 0 || !isWhite(t.char)) { + varArgs = append(varArgs, t) + } + for len(ap) <= n { + ap = append(ap, []cppToken{}) + } + ap[n] = append(ap[n], t) + } +} + +// [1]pg 2. +// +// subst(IS, FP, AP, HS, OS) /* substitute args, handle stringize and paste */ +// { +// if IS is {} then +// // ---------------------------------------------------------- A +// return hsadd(HS, OS); +// +// else if IS is # • T • IS’ and T is FP[i] then +// // ---------------------------------------------------------- B +// return subst(IS’, FP, AP, HS, OS • stringize(select(i, AP))); +// +// else if IS is ## • T • IS’ and T is FP[i] then +// { +// // ---------------------------------------------------------- C +// if select(i, AP) is {} then /* only if actuals can be empty */ +// // -------------------------------------------------- D +// return subst(IS’, FP, AP, HS, OS); +// else +// // -------------------------------------------------- E +// return subst(IS’, FP, AP, HS, glue(OS, select(i, AP))); +// } +// +// else if IS is ## • T^HS’ • IS’ then +// // ---------------------------------------------------------- F +// return subst(IS’, FP, AP, HS, glue(OS, T^HS’)); +// +// else if IS is T • ##^HS’ • IS’ and T is FP[i] then +// { +// // ---------------------------------------------------------- G +// if select(i, AP) is {} then /* only if actuals can be empty */ +// { +// // -------------------------------------------------- H +// if IS’ is T’ • IS’’ and T’ is FP[j] then +// // ------------------------------------------ I +// return subst(IS’’, FP, AP, HS, OS • select(j, AP)); +// else +// // ------------------------------------------ J +// return subst(IS’, FP, AP, HS, OS); +// } +// else +// // -------------------------------------------------- K +// return subst(##^HS’ • IS’, FP, AP, HS, OS • select(i, AP)); +// +// } +// +// else if IS is T • IS’ and T is FP[i] then +// // ---------------------------------------------------------- L +// return subst(IS’, FP, AP, HS, OS • expand(select(i, AP))); +// +// // ------------------------------------------------------------------ M +// note IS must be T^HS’ • IS’ +// return subst(IS’, FP, AP, HS, OS • T^HS’); +// } +// +// A quick overview of subst is that it walks through the input sequence, IS, +// building up an output sequence, OS, by handling each token from left to +// right. (The order that this operation takes is left to the implementation +// also, walking from left to right is more natural since the rest of the +// algorithm is constrained to this ordering.) Stringizing is easy, pasting +// requires trickier handling because the operation has a bunch of +// combinations. After the entire input sequence is finished, the updated hide +// set is applied to the output sequence, and that is the result of subst. +func (c *cpp) subst(m *Macro, is []cppToken, fp []StringID, varArgs []cppToken, ap [][]cppToken, hs hideSet, os *[]cppToken, expandDefined bool) (r []cppToken) { + var ap0 [][]cppToken + for _, v := range ap { + ap0 = append(ap0, append([]cppToken(nil), v...)) + } + // trc("==== subst: is %q, fp, %v ap@%p %v", cppToksStr(is, "|"), fp, &ap, cppToksStr2(ap)) +start: + // trc("start: is %q, fp %v, ap@%p %v, os %q", cppToksStr(is, "|"), fp, &ap, cppToksStr2(ap), cppToksStr(*os, "|")) + if len(is) == 0 { + // ---------------------------------------------------------- A + // return hsadd(HS, OS); + // trc("---- A") + // trc("subst RETURNS %q", cppToksStr(*os, "|")) + return c.hsAdd(hs, os) + } + + tok := is[0] + var arg []cppToken + if tok.char == '#' { + if len(is) > 1 && is[1].char == IDENTIFIER && m.param(varArgs, ap0, is[1].value, &arg) { + // -------------------------------------------------- B + // return subst(IS’, FP, AP, HS, OS • stringize(select(i, AP))); + // trc("---- subst B") + *os = append(*os, c.stringize(arg)) + is = is[2:] + goto start + } + } + + if tok.char == PPPASTE { + if len(is) > 1 && is[1].char == IDENTIFIER && m.param(varArgs, ap0, is[1].value, &arg) { + // -------------------------------------------------- C + // trc("---- subst C") + if len(arg) == 0 { + // TODO "only if actuals can be empty" + // ------------------------------------------ D + // return subst(IS’, FP, AP, HS, OS); + // trc("---- D") + if c := len(*os); c != 0 && (*os)[c-1].char == ',' { + *os = (*os)[:c-1] + } + is = is[2:] + goto start + } + + // -------------------------------------------------- E + // return subst(IS’, FP, AP, HS, glue(OS, select(i, AP))); + // trc("---- subst E, arg %q", cppToksStr(arg, "|")) + *os = c.glue(*os, arg) + is = is[2:] + goto start + } + + if len(is) > 1 { + // -------------------------------------------------- F + // return subst(IS’, FP, AP, HS, glue(OS, T^HS’)); + // trc("---- subst F") + *os = c.glue(*os, is[1:2]) + is = is[2:] + goto start + } + } + + if tok.char == IDENTIFIER && (len(is) > 1 && is[1].char == PPPASTE) && m.param(varArgs, ap0, tok.value, &arg) { + // ---------------------------------------------------------- G + // trc("---- subst G") + if len(arg) == 0 { + // TODO "only if actuals can be empty" + // -------------------------------------------------- H + // trc("---- subst H") + is = is[2:] // skip T## + if len(is) > 0 && is[0].char == IDENTIFIER && m.param(varArgs, ap, is[0].value, &arg) { + // -------------------------------------------------- I + // return subst(IS’’, FP, AP, HS, OS • select(j, AP)); + // trc("---- subst I") + *os = append(*os, arg...) + is = is[1:] + goto start + } else { + // -------------------------------------------------- J + // return subst(IS’, FP, AP, HS, OS); + // trc("---- subst J") + goto start + } + } + + // ---------------------------------------------------------- K + // return subst(##^HS’ • IS’, FP, AP, HS, OS • select(i, AP)); + // trc("---- subst K") + *os = append(*os, arg...) + is = is[1:] + goto start + } + + ax := -1 + if tok.char == IDENTIFIER && m.param2(varArgs, ap, tok.value, &arg, &ax) { + // ------------------------------------------ L + // return subst(IS’, FP, AP, HS, OS • expand(select(i, AP))); + // trc("---- subst L") + // if toks, ok := cache[tok.value]; ok { + // os = append(os, toks...) + // is = is[1:] + // goto start + // } + + sel := cppReader{buf: arg} + var w cppWriter + // trc("---- L(1) ap@%p %v", &ap, cppToksStr2(ap)) + c.expand(&sel, &w, expandDefined) + // trc("---- L(2) ap@%p %v", &ap, cppToksStr2(ap)) + *os = append(*os, w.toks...) + if ax >= 0 { + ap[ax] = w.toks + } + is = is[1:] + goto start + } + + // ------------------------------------------------------------------ M + // note IS must be T^HS’ • IS’ + // return subst(IS’, FP, AP, HS, OS • T^HS’); + *os = append(*os, tok) + is = is[1:] + // trc("---- subst M: is %q, os %q", cppToksStr(is, "|"), cppToksStr(*os, "|")) + goto start +} + +// paste last of left side with first of right side +// +// [1] pg. 3 +// +//TODO implement properly [0], 6.10.3.3, 2. Must rescan the resulting token(s). +// +// $ cat main.c +// #include <stdio.h> +// +// #define foo(a, b) a ## b +// +// int main() { +// int i = 42; +// i foo(+, +); +// printf("%i\n", i); +// return 0; +// } +// $ rm -f a.out ; gcc -Wall main.c && ./a.out ; echo $? +// 43 +// 0 +// $ +// +// ---------------------------------------------------------------------------- +// glue(LS,RS ) /* paste last of left side with first of right side */ +// { +// if LS is L^HS and RS is R^HS’ • RS’ then +// return L&R^(HS∩HS’) • RS’; /* undefined if L&R is invalid */ + +// // note LS must be L HS • LS’ +// return L^HS • glue(LS’,RS ); +// } +func (c *cpp) glue(ls, rs []cppToken) (out []cppToken) { + // trc("ls %q, rs %q", cppToksStr(ls, "|"), cppToksStr(rs, "|")) + if len(rs) == 0 { + return ls + } + + if len(ls) == 0 { + return rs + } + + l := ls[len(ls)-1] + ls = ls[:len(ls)-1] + r := rs[0] + rs = rs[1:] + + if l.char == IDENTIFIER && l.value == idL && r.char == STRINGLITERAL { + l.char = LONGSTRINGLITERAL + } + l.value = dict.sid(l.String() + r.String()) + return append(append(ls, l), rs...) +} + +// Given a token sequence, stringize returns a single string literal token +// containing the concatenated spellings of the tokens. +// +// [1] pg. 3 +func (c *cpp) stringize(s0 []cppToken) (r cppToken) { + // 6.10.3.2 + // + // Each occurrence of white space between the argument’s preprocessing + // tokens becomes a single space character in the character string + // literal. + s := make([]cppToken, 0, len(s0)) + var last rune + for i := range s0 { + t := s0[i] + if isWhite(t.char) { + t.char = ' ' + t.value = idSpace + if last == ' ' { + continue + } + } + + last = t.char + s = append(s, t) + } + + // White space before the first preprocessing token and after the last + // preprocessing token composing the argument is deleted. + s = c.trim(s) + + // The character string literal corresponding to an empty argument is + // "" + if len(s) == 0 { + r.hs = nil + r.char = STRINGLITERAL + r.value = idEmptyString + return r + } + + var a []string + // Otherwise, the original spelling of each preprocessing token in the + // argument is retained in the character string literal, except for + // special handling for producing the spelling of string literals and + // character constants: a \ character is inserted before each " and \ + // character of a character constant or string literal (including the + // delimiting " characters), except that it is implementation-defined + // whether a \ character is inserted before the \ character beginning a + // universal character name. + for _, v := range s { + s := v.String() + switch v.char { + case CHARCONST, STRINGLITERAL: + s = strings.ReplaceAll(s, `\`, `\\`) + s = strings.ReplaceAll(s, `"`, `\"`) + case LONGCHARCONST, LONGSTRINGLITERAL: + panic("TODO") + } + a = append(a, s) + } + r = s[0] + r.hs = nil + r.char = STRINGLITERAL + r.value = dict.sid(`"` + strings.Join(a, "") + `"`) + return r +} + +func (c *cpp) trim(toks []cppToken) []cppToken { + for len(toks) != 0 && isWhite(toks[0].char) { + toks = toks[1:] + } + for len(toks) != 0 && isWhite(toks[len(toks)-1].char) { + toks = toks[:len(toks)-1] + } + return toks +} + +func (c *cpp) hsAdd(hs hideSet, toks *[]cppToken) []cppToken { + for i, v := range *toks { + if v.hs == nil { + v.hs = hideSet{} + } + for k, w := range hs { + v.hs[k] = w + } + v.file = c.file + (*toks)[i] = v + } + return *toks +} + +func (c *cpp) parseDefined(tok cppToken, r tokenReader, w tokenWriter) { + toks := []cppToken{tok} + if tok = c.scanToNonBlankToken(&toks, r, w); tok.char < 0 { + return + } + + switch tok.char { + case IDENTIFIER: + // ok + case '(': + if tok = c.scanToNonBlankToken(&toks, r, w); tok.char < 0 { + return + } + + if tok.char != IDENTIFIER { + w.writes(toks) + return + } + + tok2 := c.scanToNonBlankToken(&toks, r, w) + if tok2.char < 0 { + return + } + + if tok2.char != ')' { + w.writes(toks) + return + } + } + + tok.char = PPNUMBER + switch _, ok := c.macros[tok.value]; { + case ok: + tok.value = idOne + default: + tok.value = idZero + } + w.write(tok) +} + +func (c *cpp) scanToNonBlankToken(toks *[]cppToken, r tokenReader, w tokenWriter) cppToken { + tok, ok := r.read() + if !ok { + w.writes(*toks) + tok.char = -1 + return tok + } + + *toks = append(*toks, tok) + if tok.char == ' ' || tok.char == '\n' { + if tok, ok = r.read(); !ok { + w.writes(*toks) + tok.char = -1 + return tok + } + + *toks = append(*toks, tok) + } + return (*toks)[len(*toks)-1] +} + +// [0], 6.10.1 +func (c *cpp) evalInclusionCondition(expr []token3) (r bool) { + if !c.intmaxChecked { + if m := c.macros[idIntMaxWidth]; m != nil && len(m.repl) != 0 { + if val := c.intMaxWidth(); val != 0 && val != 64 { + c.err(m.name, "%s is %v, but only 64 is supported", idIntMaxWidth, val) + } + } + c.intmaxChecked = true + } + + val := c.eval(expr) + return val != nil && c.isNonZero(val) +} + +func (c *cpp) intMaxWidth() int64 { + if m := c.macros[idIntMaxWidth]; m != nil && len(m.repl) != 0 { + switch x := c.eval(m.repl).(type) { + case nil: + return 0 + case int64: + return x + case uint64: + return int64(x) + default: + panic(internalError()) + } + } + return 0 +} + +func (c *cpp) eval(expr []token3) interface{} { + toks := make([]cppToken, len(expr)) + for i, v := range expr { + toks[i] = cppToken{token4{token3: v}, nil} + } + var w cppWriter + c.expand(&cppReader{buf: toks}, &w, true) + toks = w.toks + p := 0 + for _, v := range toks { + switch v.char { + case ' ', '\n': + // nop + default: + toks[p] = v + p++ + } + } + toks = toks[:p] + s := cppScanner(toks) + val := c.expression(&s, true) + switch s.peek().char { + case -1, '#': + // ok + default: + t := s.peek() + c.err(t, "unexpected %s", tokName(t.char)) + return nil + } + return val +} + +// [0], 6.5.17 Comma operator +// +// expression: +// assignment-expression +// expression , assignment-expression +func (c *cpp) expression(s *cppScanner, eval bool) interface{} { + for { + r := c.assignmentExpression(s, eval) + if s.peek().char != ',' { + return r + } + + s.next() + } +} + +// [0], 6.5.16 Assignment operators +// +// assignment-expression: +// conditional-expression +// unary-expression assignment-operator assignment-expression +// +// assignment-operator: one of +// = *= /= %= += -= <<= >>= &= ^= |= +func (c *cpp) assignmentExpression(s *cppScanner, eval bool) interface{} { + return c.conditionalExpression(s, eval) +} + +// [0], 6.5.15 Conditional operator +// +// conditional-expression: +// logical-OR-expression +// logical-OR-expression ? expression : conditional-expression +func (c *cpp) conditionalExpression(s *cppScanner, eval bool) interface{} { + expr := c.logicalOrExpression(s, eval) + if s.peek().char == '?' { + s.next() + exprIsNonZero := c.isNonZero(expr) + expr2 := c.conditionalExpression(s, exprIsNonZero) + if tok := s.peek(); tok.char != ':' { + c.err(tok, "expected ':'") + return expr + } + + s.next() + expr3 := c.conditionalExpression(s, !exprIsNonZero) + + // [0] 6.5.15 + // + // 5. 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. + x := c.operand(expr2) + y := c.operand(expr3) + if x != nil && y != nil { + x, y = usualArithmeticConversions(c.ctx, nil, x, y, false) + expr2 = c.fromOperand(x) + expr3 = c.fromOperand(y) + } + + switch { + case exprIsNonZero: + expr = expr2 + default: + expr = expr3 + } + } + return expr +} + +func (c *cpp) operand(v interface{}) Operand { + switch x := v.(type) { + case int64: + return &operand{typ: &typeBase{size: 8, kind: byte(LongLong), flags: fSigned}, value: Int64Value(x)} + case uint64: + return &operand{typ: &typeBase{size: 8, kind: byte(ULongLong)}, value: Uint64Value(x)} + default: + return nil + } +} + +func (c *cpp) fromOperand(op Operand) interface{} { + switch x := op.Value().(type) { + case Int64Value: + return int64(x) + case Uint64Value: + return uint64(x) + default: + return nil + } +} + +// [0], 6.5.14 Logical OR operator +// +// logical-OR-expression: +// logical-AND-expression +// logical-OR-expression || logical-AND-expression +func (c *cpp) logicalOrExpression(s *cppScanner, eval bool) interface{} { + lhs := c.logicalAndExpression(s, eval) + for s.peek().char == OROR { + s.next() + if c.isNonZero(lhs) { + eval = false + } + rhs := c.logicalAndExpression(s, eval) + if c.isNonZero(lhs) || c.isNonZero(rhs) { + lhs = int64(1) + } + } + return lhs +} + +// [0], 6.5.13 Logical AND operator +// +// logical-AND-expression: +// inclusive-OR-expression +// logical-AND-expression && inclusive-OR-expression +func (c *cpp) logicalAndExpression(s *cppScanner, eval bool) interface{} { + lhs := c.inclusiveOrExpression(s, eval) + for s.peek().char == ANDAND { + s.next() + if c.isZero(lhs) { + eval = false + } + rhs := c.inclusiveOrExpression(s, eval) + if c.isZero(lhs) || c.isZero(rhs) { + lhs = int64(0) + } + } + return lhs +} + +func (c *cpp) isZero(val interface{}) bool { + switch x := val.(type) { + case int64: + return x == 0 + case uint64: + return x == 0 + } + panic(internalError()) +} + +// [0], 6.5.12 Bitwise inclusive OR operator +// +// inclusive-OR-expression: +// exclusive-OR-expression +// inclusive-OR-expression | exclusive-OR-expression +func (c *cpp) inclusiveOrExpression(s *cppScanner, eval bool) interface{} { + lhs := c.exclusiveOrExpression(s, eval) + for s.peek().char == '|' { + s.next() + rhs := c.exclusiveOrExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x | y + case uint64: + lhs = uint64(x) | y + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x | uint64(y) + case uint64: + lhs = x | y + } + } + } + } + return lhs +} + +// [0], 6.5.11 Bitwise exclusive OR operator +// +// exclusive-OR-expression: +// AND-expression +// exclusive-OR-expression ^ AND-expression +func (c *cpp) exclusiveOrExpression(s *cppScanner, eval bool) interface{} { + lhs := c.andExpression(s, eval) + for s.peek().char == '^' { + s.next() + rhs := c.andExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x ^ y + case uint64: + lhs = uint64(x) ^ y + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x ^ uint64(y) + case uint64: + lhs = x ^ y + } + } + } + } + return lhs +} + +// [0], 6.5.10 Bitwise AND operator +// +// AND-expression: +// equality-expression +// AND-expression & equality-expression +func (c *cpp) andExpression(s *cppScanner, eval bool) interface{} { + lhs := c.equalityExpression(s, eval) + for s.peek().char == '&' { + s.next() + rhs := c.equalityExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x & y + case uint64: + lhs = uint64(x) & y + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x & uint64(y) + case uint64: + lhs = x & y + } + } + } + } + return lhs +} + +// [0], 6.5.9 Equality operators +// +// equality-expression: +// relational-expression +// equality-expression == relational-expression +// equality-expression != relational-expression +func (c *cpp) equalityExpression(s *cppScanner, eval bool) interface{} { + lhs := c.relationalExpression(s, eval) + for { + var v bool + switch s.peek().char { + case EQ: + s.next() + rhs := c.relationalExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + v = x == y + case uint64: + v = uint64(x) == y + } + case uint64: + switch y := rhs.(type) { + case int64: + v = x == uint64(y) + case uint64: + v = x == y + } + } + } + case NEQ: + s.next() + rhs := c.relationalExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + v = x != y + case uint64: + v = uint64(x) != y + } + case uint64: + switch y := rhs.(type) { + case int64: + v = x != uint64(y) + case uint64: + v = x != y + } + } + } + default: + return lhs + } + switch { + case v: + lhs = int64(1) + default: + lhs = int64(0) + } + } +} + +// [0], 6.5.8 Relational operators +// +// relational-expression: +// shift-expression +// relational-expression < shift-expression +// relational-expression > shift-expression +// relational-expression <= shift-expression +// relational-expression >= shift-expression +func (c *cpp) relationalExpression(s *cppScanner, eval bool) interface{} { + lhs := c.shiftExpression(s, eval) + for { + var v bool + switch s.peek().char { + case '<': + s.next() + rhs := c.shiftExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + v = x < y + case uint64: + v = uint64(x) < y + } + case uint64: + switch y := rhs.(type) { + case int64: + v = x < uint64(y) + case uint64: + v = x < y + } + } + } + case '>': + s.next() + rhs := c.shiftExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + v = x > y + case uint64: + v = uint64(x) > y + } + case uint64: + switch y := rhs.(type) { + case int64: + v = x > uint64(y) + case uint64: + v = x > y + } + } + } + case LEQ: + s.next() + rhs := c.shiftExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + v = x <= y + case uint64: + v = uint64(x) <= y + } + case uint64: + switch y := rhs.(type) { + case int64: + v = x <= uint64(y) + case uint64: + v = x <= y + } + } + } + case GEQ: + s.next() + rhs := c.shiftExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + v = x >= y + case uint64: + v = uint64(x) >= y + } + case uint64: + switch y := rhs.(type) { + case int64: + v = x >= uint64(y) + case uint64: + v = x >= y + } + } + } + default: + return lhs + } + switch { + case v: + lhs = int64(1) + default: + lhs = int64(0) + } + } +} + +// [0], 6.5.7 Bitwise shift operators +// +// shift-expression: +// additive-expression +// shift-expression << additive-expression +// shift-expression >> additive-expression +func (c *cpp) shiftExpression(s *cppScanner, eval bool) interface{} { + lhs := c.additiveExpression(s, eval) + for { + switch s.peek().char { + case LSH: + s.next() + rhs := c.additiveExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x << uint(y) + case uint64: + lhs = uint64(x) << uint(y) + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x << uint(y) + case uint64: + lhs = x << uint(y) + } + } + } + case RSH: + s.next() + rhs := c.additiveExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x >> uint(y) + case uint64: + lhs = uint64(x) >> uint(y) + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x >> uint(y) + case uint64: + lhs = x >> uint(y) + } + } + } + default: + return lhs + } + } +} + +// [0], 6.5.6 Additive operators +// +// additive-expression: +// multiplicative-expression +// additive-expression + multiplicative-expression +// additive-expression - multiplicative-expression +func (c *cpp) additiveExpression(s *cppScanner, eval bool) interface{} { + lhs := c.multiplicativeExpression(s, eval) + for { + switch s.peek().char { + case '+': + s.next() + rhs := c.multiplicativeExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x + y + case uint64: + lhs = uint64(x) + y + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x + uint64(y) + case uint64: + lhs = x + y + } + } + } + case '-': + s.next() + rhs := c.multiplicativeExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x - y + case uint64: + lhs = uint64(x) - y + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x - uint64(y) + case uint64: + lhs = x - y + } + } + } + default: + return lhs + } + } +} + +// [0], 6.5.5 Multiplicative operators +// +// multiplicative-expression: +// unary-expression // [0], 6.10.1, 1. +// multiplicative-expression * unary-expression +// multiplicative-expression / unary-expression +// multiplicative-expression % unary-expression +func (c *cpp) multiplicativeExpression(s *cppScanner, eval bool) interface{} { + lhs := c.unaryExpression(s, eval) + for { + switch s.peek().char { + case '*': + s.next() + rhs := c.unaryExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + lhs = x * y + case uint64: + lhs = uint64(x) * y + } + case uint64: + switch y := rhs.(type) { + case int64: + lhs = x * uint64(y) + case uint64: + lhs = x * y + } + } + } + case '/': + tok := s.next() + rhs := c.unaryExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = x / y + case uint64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = uint64(x) / y + } + case uint64: + switch y := rhs.(type) { + case int64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = x / uint64(y) + case uint64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = x / y + } + } + } + case '%': + tok := s.next() + rhs := c.unaryExpression(s, eval) + if eval { + switch x := lhs.(type) { + case int64: + switch y := rhs.(type) { + case int64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = x % y + case uint64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = uint64(x) % y + } + case uint64: + switch y := rhs.(type) { + case int64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = x % uint64(y) + case uint64: + if y == 0 { + c.err(tok, "division by zero") + break + } + + lhs = x % y + } + } + } + default: + return lhs + } + } +} + +// [0], 6.5.3 Unary operators +// +// unary-expression: +// primary-expression +// unary-operator unary-expression +// +// unary-operator: one of +// + - ~ ! +func (c *cpp) unaryExpression(s *cppScanner, eval bool) interface{} { + switch s.peek().char { + case '+': + s.next() + return c.unaryExpression(s, eval) + case '-': + s.next() + expr := c.unaryExpression(s, eval) + if eval { + switch x := expr.(type) { + case int64: + expr = -x + case uint64: + expr = -x + } + } + return expr + case '~': + s.next() + expr := c.unaryExpression(s, eval) + if eval { + switch x := expr.(type) { + case int64: + expr = ^x + case uint64: + expr = ^x + } + } + return expr + case '!': + s.next() + expr := c.unaryExpression(s, eval) + if eval { + var v bool + switch x := expr.(type) { + case int64: + v = x == 0 + case uint64: + v = x == 0 + } + switch { + case v: + expr = int64(1) + default: + expr = int64(0) + } + } + return expr + default: + return c.primaryExpression(s, eval) + } +} + +// [0], 6.5.1 Primary expressions +// +// primary-expression: +// identifier +// constant +// ( expression ) +func (c *cpp) primaryExpression(s *cppScanner, eval bool) interface{} { + switch tok := s.peek(); tok.char { + case CHARCONST, LONGCHARCONST: + s.next() + r := charConst(c.ctx, tok) + return int64(r) + case IDENTIFIER: + if c.ctx.evalIdentError { + panic("cannot evaluate identifier") + } + + s.next() + if s.peek().char == '(' { + s.next() + n := 1 + loop: + for n != 0 { + switch s.peek().char { + case '(': + n++ + case ')': + n-- + case -1: + c.err(s.peek(), "expected )") + break loop + } + s.next() + } + } + return int64(0) + case PPNUMBER: + s.next() + return c.intConst(tok) + case '(': + s.next() + expr := c.expression(s, eval) + if s.peek().char == ')' { + s.next() + } + return expr + default: + return int64(0) + } +} + +// [0], 6.4.4.1 Integer constants +// +// integer-constant: +// decimal-constant integer-suffix_opt +// octal-constant integer-suffix_opt +// hexadecimal-constant integer-suffix_opt +// +// decimal-constant: +// nonzero-digit +// decimal-constant digit +// +// octal-constant: +// 0 +// octal-constant octal-digit +// +// hexadecimal-prefix: one of +// 0x 0X +// +// integer-suffix_opt: one of +// u ul ull l lu ll llu +func (c *cpp) intConst(tok cppToken) (r interface{}) { + var n uint64 + s0 := tok.String() + s := strings.TrimRight(s0, "uUlL") + switch { + case strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X"): + var err error + if n, err = strconv.ParseUint(s[2:], 16, 64); err != nil { + c.err(tok, "%v", err) + return int64(0) + } + case strings.HasPrefix(s, "0"): + var err error + if n, err = strconv.ParseUint(s, 8, 64); err != nil { + c.err(tok, "%v", err) + return int64(0) + } + default: + var err error + if n, err = strconv.ParseUint(s, 10, 64); err != nil { + c.err(tok, "%v", err) + return int64(0) + } + } + + suffix := s0[len(s):] + if suffix == "" { + if n > math.MaxInt64 { + return n + } + + return int64(n) + } + + switch suffix = strings.ToLower(suffix); suffix { + default: + c.err(tok, "invalid suffix: %v", s0) + fallthrough + case + "l", + "ll": + + if n > math.MaxInt64 { + return n + } + + return int64(n) + case + "llu", + "lu", + "u", + "ul", + "ull": + + return n + } +} + +func charConst(ctx *context, tok cppToken) rune { + s := tok.String() + switch tok.char { + case LONGCHARCONST: + s = s[1:] // Remove leading 'L'. + fallthrough + case CHARCONST: + s = s[1 : len(s)-1] // Remove outer 's. + if len(s) == 1 { + return rune(s[0]) + } + + var r rune + var n int + switch s[0] { + case '\\': + r, n = decodeEscapeSequence(ctx, tok, s) + if r < 0 { + r = -r + } + default: + r, n = utf8.DecodeRuneInString(s) + } + if n != len(s) { + ctx.errNode(&tok, "invalid character constant") + } + return r + } + panic(internalError()) +} + +// escape-sequence {simple-sequence}|{octal-escape-sequence}|{hexadecimal-escape-sequence}|{universal-character-name} +// simple-sequence \\['\x22?\\abfnrtv] +// octal-escape-sequence \\{octal-digit}{octal-digit}?{octal-digit}? +// hexadecimal-escape-sequence \\x{hexadecimal-digit}+ +func decodeEscapeSequence(ctx *context, tok cppToken, s string) (rune, int) { + if s[0] != '\\' { + panic(internalError()) + } + + if len(s) == 1 { + return rune(s[0]), 1 + } + + r := rune(s[1]) + switch r { + case '\'', '"', '?', '\\': + return r, 2 + case 'a': + return 7, 2 + case 'b': + return 8, 2 + case 'e': + return 0x1b, 2 + case 'f': + return 12, 2 + case 'n': + return 10, 2 + case 'r': + return 13, 2 + case 't': + return 9, 2 + case 'v': + return 11, 2 + case 'x': + v, n := 0, 2 + loop2: + for i := 2; i < len(s); i++ { + r := s[i] + switch { + case r >= '0' && r <= '9', r >= 'a' && r <= 'f', r >= 'A' && r <= 'F': + v = v<<4 | decodeHex(r) + n++ + default: + break loop2 + } + } + return -rune(v & 0xff), n + case 'u', 'U': + return decodeUCN(s) + } + + if r < '0' || r > '7' { + panic(internalError()) + } + + v, n := 0, 1 + ok := false +loop: + for i := 1; i < len(s); i++ { + r := s[i] + switch { + case i < 4 && r >= '0' && r <= '7': + ok = true + v = v<<3 | (int(r) - '0') + n++ + default: + break loop + } + } + if !ok { + ctx.errNode(&tok, "invalid octal sequence") + } + return -rune(v), n +} + +// universal-character-name \\u{hex-quad}|\\U{hex-quad}{hex-quad} +func decodeUCN(s string) (rune, int) { + if s[0] != '\\' { + panic(internalError()) + } + + s = s[1:] + switch s[0] { + case 'u': + return rune(decodeHexQuad(s[1:])), 6 + case 'U': + return rune(decodeHexQuad(s[1:])<<16 | decodeHexQuad(s[5:])), 10 + } + panic(internalError()) +} + +// hex-quad {hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit} +func decodeHexQuad(s string) int { + n := 0 + for i := 0; i < 4; i++ { + n = n<<4 | decodeHex(s[i]) + } + return n +} + +func decodeHex(r byte) int { + switch { + case r >= '0' && r <= '9': + return int(r) - '0' + default: + x := int(r) &^ 0x20 + return x - 'A' + 10 + } +} + +func (c *cpp) isNonZero(val interface{}) bool { + switch x := val.(type) { + case int64: + return x != 0 + case uint64: + return x != 0 + } + panic(internalError()) +} + +type ppLine interface { + getToks() []token3 +} + +type ppIfGroupDirective interface { + evalInclusionCondition(*cpp) bool +} + +type ppElifDirective struct { + toks []token3 + expr []token3 +} + +func (n *ppElifDirective) getToks() []token3 { return n.toks } + +type ppElseDirective struct { + toks []token3 +} + +func (n *ppElseDirective) getToks() []token3 { return n.toks } + +type ppEndifDirective struct { + toks []token3 +} + +func (n *ppEndifDirective) getToks() []token3 { return n.toks } + +type ppEmptyDirective struct { + toks []token3 +} + +func (n *ppEmptyDirective) getToks() []token3 { return n.toks } + +func (n *ppEmptyDirective) translationPhase4(c *cpp) { + // nop +} + +type ppIncludeDirective struct { + arg []token3 + toks []token3 + + includeNext bool // false: #include, true: #include_next +} + +func (n *ppIncludeDirective) getToks() []token3 { return n.toks } + +func (n *ppIncludeDirective) translationPhase4(c *cpp) { + if c.ctx.cfg.ignoreIncludes { + return + } + + args := make([]cppToken, 0, len(n.arg)) + for _, v := range n.arg { + switch v.char { + case ' ', '\t', '\v', '\f': + // nop + default: + args = append(args, cppToken{token4{token3: v}, nil}) + } + } + var sb strings.Builder + for _, v := range args { + sb.WriteString(v.String()) + } + nm := strings.TrimSpace(sb.String()) + if nm == "" { + c.err(n.toks[0], "invalid empty include argument") + return + } + + switch nm[0] { + case '"', '<': + // ok + default: + var w cppWriter + c.expand(&cppReader{buf: args}, &w, false) + x := 0 + for _, v := range w.toks { + switch v.char { + case ' ', '\t', '\v', '\f': + // nop + default: + w.toks[x] = v + x++ + } + } + w.toks = w.toks[:x] + nm = strings.TrimSpace(cppToksStr(w.toks, "")) + } + toks := n.toks + if c.ctx.cfg.RejectIncludeNext { + c.err(toks[0], "#include_next is a GCC extension") + return + } + + if c.ctx.cfg.fakeIncludes { + c.send([]token3{{char: STRINGLITERAL, value: dict.sid(nm), src: dict.sid(nm)}, {char: '\n', value: idNL}}) + return + } + + if re := c.ctx.cfg.IgnoreInclude; re != nil && re.MatchString(nm) { + return + } + + if c.includeLevel == maxIncludeLevel { + c.err(toks[0], "too many include levels") + return + } + + c.includeLevel++ + + defer func() { c.includeLevel-- }() + + var ( + b byte + paths []string + sys bool + ) + switch { + case nm != "" && nm[0] == '"': + paths = c.ctx.includePaths + b = '"' + case nm != "" && nm[0] == '<': + paths = c.ctx.sysIncludePaths + sys = true + b = '>' + case nm == "": + c.err(toks[0], "invalid empty include argument") + return + default: + c.err(toks[0], "invalid include argument %s", nm) + return + } + + x := strings.IndexByte(nm[1:], b) + if x < 0 { + c.err(toks[0], "invalid include argument %s", nm) + return + } + + nm = filepath.FromSlash(nm[1 : x+1]) + var path string + switch { + case filepath.IsAbs(nm): + path = nm + default: + dir := filepath.Dir(c.file.Name()) + if n.includeNext { + nmDir, _ := filepath.Split(nm) + for i, v := range paths { + if w, err := filepath.Abs(v); err == nil { + v = w + } + v = filepath.Join(v, nmDir) + if v == dir { + paths = paths[i+1:] + break + } + } + } + for _, v := range paths { + if v == "@" { + v = dir + } + + p := filepath.Join(v, nm) + fi, err := c.ctx.statFile(p, sys) + if err != nil || fi.IsDir() { + continue + } + + path = p + break + } + } + + if path == "" { + wd, _ := os.Getwd() + c.err(toks[0], "include file not found: %s (wd %s)\nsearch paths:\n\t%s", nm, wd, strings.Join(paths, "\n\t")) + return + } + + if h := c.ctx.cfg.IncludeFileHandler; h != nil { + var position gotoken.Position + if p := toks[0].Pos(); p.IsValid() { + position = gotoken.Position(c.file.PositionFor(p, true)) + } + apath, err := filepath.Abs(path) + if err != nil { + c.err(toks[0], "%s: cannot compute absolute path: %v", path, err) + } + h(position, apath) + } + cf, err := cache.getFile(c.ctx, path, sys, false) + if err != nil { + c.err(toks[0], "%s: %v", path, err) + return + } + + pf, err := cf.ppFile() + if err != nil { + c.err(toks[0], "%s: %v", path, err) + return + } + + saveFile := c.file + saveFileMacro := c.fileMacro.repl[0].value + + c.file = pf.file + c.fileMacro.repl[0].value = dict.sid(fmt.Sprintf("%q", c.file.Name())) + + defer func() { + c.file = saveFile + c.fileMacro.repl[0].value = saveFileMacro + }() + + pf.translationPhase4(c) +} + +func (c *cpp) send(toks []token3) { + c.in <- toks + <-c.rq +} + +func (c *cpp) identicalReplacementLists(a, b []token3) bool { + for len(a) != 0 && a[0].char == ' ' { + a = a[1:] + } + for len(b) != 0 && b[0].char == ' ' { + b = b[1:] + } + for len(a) != 0 && a[len(a)-1].char == ' ' { + a = a[:len(a)-1] + } + for len(b) != 0 && b[len(b)-1].char == ' ' { + b = b[:len(b)-1] + } + if len(a) != len(b) { + return false + } + + for i, v := range a { + w := b[i] + if v.char != w.char || v.value != w.value { + return false + } + } + return true +} + +func stringConst(ctx *context, t cppToken) string { + s := t.String() + switch t.char { + case LONGSTRINGLITERAL: + s = s[1:] // Remove leading 'L'. + fallthrough + case STRINGLITERAL: + var buf bytes.Buffer + for i := 1; i < len(s)-1; { + switch c := s[i]; c { + case '\\': + r, n := decodeEscapeSequence(ctx, t, s[i:]) + switch { + case r < 0: + buf.WriteByte(byte(-r)) + default: + buf.WriteRune(r) + } + i += n + default: + buf.WriteByte(c) + i++ + } + } + return buf.String() + } + panic(internalError()) +} + +// -------------------------------------------------------- Translation phase 4 + +// [0], 5.1.1.2, 4 +// +// Preprocessing directives are executed, macro invocations are expanded, and +// _Pragma unary operator expressions are executed. If a character sequence +// that matches the syntax of a universal character name is produced by token +// concatenation (6.10.3.3), the behavior is undefined. A #include +// preprocessing directive causes the named header or source file to be +// processed from phase 1 through phase 4, recursively. All preprocessing +// directives are then deleted. +func (c *cpp) translationPhase4(in []source) chan *[]token4 { + c.rq = make(chan struct{}) // Must be unbufferred + c.in = make(chan []token3) // Must be unbufferred + c.out = make(chan *[]token4, 10) //DONE benchmark tuned + + go func() { + defer close(c.out) + + c.expand(c, c, false) + }() + + go func() { + defer close(c.in) + + for _, v := range in { + pf, err := v.ppFile() + if err != nil { + c.err(nil, "%s", err) + break + } + + c.file = pf.file + c.fileMacro.repl[0].value = dict.sid(fmt.Sprintf("%q", c.file.Name())) + pf.translationPhase4(c) + } + }() + + return c.out +} + +type ppErrorDirective struct { + toks []token3 + msg []token3 +} + +func (n *ppErrorDirective) getToks() []token3 { return n.toks } + +func (n *ppErrorDirective) translationPhase4(c *cpp) { + var b strings.Builder + for _, v := range n.msg { + b.WriteString(v.String()) + } + c.err(n.toks[0], "%s", strings.TrimSpace(b.String())) +} + +type ppPragmaDirective struct { + toks []token3 + args []token3 +} + +func (n *ppPragmaDirective) getToks() []token3 { return n.toks } + +func (n *ppPragmaDirective) translationPhase4(c *cpp) { parsePragma(c, n.args) } + +func parsePragma(c *cpp, args0 []token3) { + if len(args0) == 1 { // \n + return + } + + if t := args0[0]; t.char == IDENTIFIER && t.value == idSTDC { + p := t + p.char = PRAGMASTDC + p.value = idPragmaSTDC + send := []token3{p, {char: ' ', value: idSpace, src: idSpace, pos: t.pos}} + args := ltrim3(args0[1:]) + if len(args) == 0 { + c.err(args[0], "expected argument of STDC") + return + } + + if t = args[0]; t.char != IDENTIFIER { + c.err(t, "expected identifier") + return + } + + switch t.value { + case idFPContract, idFenvAccess, idCxLimitedRange: + // ok + default: + c.err(t, "expected FP_CONTRACT or FENV_ACCESS or CX_LIMITED_RANGE") + return + } + + args = ltrim3(args[1:]) + if len(args) == 0 { + c.err(args[0], "expected ON or OFF or DEFAULT") + return + } + + if t = args[0]; t.char != IDENTIFIER { + c.err(t, "expected identifier") + return + } + + switch t.value { + case idOn, idOff, idDefault: + c.writes(c.cppToks(append(send, args0...))) + default: + c.err(t, "expected ON or OFF or DEFAULT") + return + } + } + + if c.ctx.cfg.PragmaHandler == nil { + return + } + + var toks []cppToken + for _, v := range args0[:len(args0)-1] { + toks = append(toks, cppToken{token4: token4{file: c.file, token3: v}}) + } + if len(toks) == 0 { + return + } + + var toks2 []Token + var sep StringID + for _, tok := range toks { + switch tok.char { + case ' ', '\n': + if c.ctx.cfg.PreserveOnlyLastNonBlankSeparator { + if strings.TrimSpace(tok.value.String()) != "" { + sep = tok.value + } + break + } + + switch { + case sep != 0: + sep = dict.sid(sep.String() + tok.String()) //TODO quadratic + default: + sep = tok.value + } + default: + var t Token + t.Rune = tok.char + t.Sep = sep + t.Value = tok.value + t.file = tok.file + t.pos = tok.pos + toks2 = append(toks2, t) + sep = 0 + } + } + if len(toks2) == 0 { + return + } + + // dbg("%v: %q", c.file.PositionFor(args0[0].Pos(), true), tokStr(toks2, "|")) + c.ctx.cfg.PragmaHandler(&pragma{tok: toks[0], c: c}, toks2) +} + +type ppNonDirective struct { + toks []token3 +} + +func (n *ppNonDirective) getToks() []token3 { return n.toks } + +func (n *ppNonDirective) translationPhase4(c *cpp) { + // nop +} + +type ppTextLine struct { + toks []token3 +} + +func (n *ppTextLine) getToks() []token3 { return n.toks } + +func (n *ppTextLine) translationPhase4(c *cpp) { c.send(n.toks) } + +type ppLineDirective struct { + toks []token3 + args []token3 + nextPos int +} + +func (n *ppLineDirective) getToks() []token3 { return n.toks } + +func (n *ppLineDirective) translationPhase4(c *cpp) { + toks := expandArgs(c, n.args) + if len(toks) == 0 { + return + } + + switch t := toks[0]; t.char { + case PPNUMBER: + ln, err := strconv.ParseInt(t.String(), 10, 31) + if err != nil || ln < 1 { + c.err(t, "expected positive integer less or equal 2147483647") + return + } + + for len(toks) != 0 && toks[0].char == ' ' { + toks = toks[1:] + } + if len(toks) == 1 { + c.file.AddLineInfo(int(n.nextPos)-1, c.file.Name(), int(ln)) + return + } + + toks = toks[1:] + for len(toks) != 0 && toks[0].char == ' ' { + toks = toks[1:] + } + if len(toks) == 0 { + c.file.AddLineInfo(int(n.nextPos)-1, c.file.Name(), int(ln)) + return + } + + switch t := toks[0]; t.char { + case STRINGLITERAL: + s := t.String() + s = s[1 : len(s)-1] + c.file.AddLineInfo(int(n.nextPos)-1, s, int(ln)) + c.fileMacro.repl[0].value = t.value + for len(toks) != 0 && toks[0].char == ' ' { + toks = toks[1:] + } + if len(toks) != 0 && c.ctx.cfg.RejectLineExtraTokens { + c.err(toks[0], "expected new-line") + } + default: + c.err(t, "expected string literal") + return + } + default: + c.err(toks[0], "expected integer literal") + return + } +} + +func expandArgs(c *cpp, args []token3) []cppToken { + var w cppWriter + var toks []cppToken + for _, v := range args { + toks = append(toks, cppToken{token4: token4{file: c.file, token3: v}}) + } + c.expand(&cppReader{buf: toks}, &w, true) + return w.toks +} + +type ppUndefDirective struct { + name token3 + toks []token3 +} + +func (n *ppUndefDirective) getToks() []token3 { return n.toks } + +func (n *ppUndefDirective) translationPhase4(c *cpp) { + nm := n.name.value + if _, ok := protectedMacros[nm]; ok || nm == idDefined { + c.err(n.name, "cannot undefine a protected name") + return + } + + // dbg("#undef %s", nm) + delete(c.macros, nm) +} + +type ppIfdefDirective struct { + name StringID + toks []token3 +} + +func (n *ppIfdefDirective) evalInclusionCondition(c *cpp) bool { _, ok := c.macros[n.name]; return ok } + +func (n *ppIfdefDirective) getToks() []token3 { return n.toks } + +type ppIfndefDirective struct { + name StringID + toks []token3 +} + +func (n *ppIfndefDirective) evalInclusionCondition(c *cpp) bool { + _, ok := c.macros[n.name] + return !ok +} + +func (n *ppIfndefDirective) getToks() []token3 { return n.toks } + +type ppIfDirective struct { + toks []token3 + expr []token3 +} + +func (n *ppIfDirective) getToks() []token3 { return n.toks } + +func (n *ppIfDirective) evalInclusionCondition(c *cpp) bool { + return c.evalInclusionCondition(n.expr) +} + +type ppDefineObjectMacroDirective struct { + name token3 + toks []token3 + replacementList []token3 +} + +func (n *ppDefineObjectMacroDirective) getToks() []token3 { return n.toks } + +func (n *ppDefineObjectMacroDirective) translationPhase4(c *cpp) { + nm := n.name.value + m := c.macros[nm] + if m != nil { + if _, ok := protectedMacros[nm]; ok || nm == idDefined { + c.err(n.name, "cannot define protected name") + return + } + + if m.isFnLike { + c.err(n.name, "redefinition of a function-like macro with an object-like one") + } + + if !c.identicalReplacementLists(n.replacementList, m.repl) && c.ctx.cfg.RejectIncompatibleMacroRedef { + c.err(n.name, "redefinition with different replacement list") + return + } + } + + // find first non-blank token to claim as our location + var pos int32 + for _, t := range n.toks { + if t.char != ' ' { + pos = t.pos + break + } + } + + // dbg("#define %s %s // %v", n.name, tokStr(n.replacementList, " "), c.file.PositionFor(n.name.Pos(), true)) + c.macros[nm] = &Macro{pos: pos, name: token4{token3: n.name, file: c.file}, repl: n.replacementList} + if nm != idGNUC { + return + } + + c.ctx.keywords = gccKeywords +} + +type ppDefineFunctionMacroDirective struct { + identifierList []token3 + toks []token3 + replacementList []token3 + + name token3 + + namedVariadic bool // foo..., note no comma before ellipsis. + variadic bool +} + +func (n *ppDefineFunctionMacroDirective) getToks() []token3 { return n.toks } + +func (n *ppDefineFunctionMacroDirective) translationPhase4(c *cpp) { + nm := n.name.value + m := c.macros[nm] + if m != nil { + if _, ok := protectedMacros[nm]; ok || nm == idDefined { + c.err(n.name, "cannot define protected name") + return + } + + if !m.isFnLike && c.ctx.cfg.RejectIncompatibleMacroRedef { + c.err(n.name, "redefinition of an object-like macro with a function-like one") + return + } + + ok := len(m.fp) == len(n.identifierList) + if ok { + for i, v := range m.fp { + if v != n.identifierList[i].value { + ok = false + break + } + } + } + if !ok && (len(n.replacementList) != 0 || len(m.repl) != 0) && c.ctx.cfg.RejectIncompatibleMacroRedef { + c.err(n.name, "redefinition with different formal parameters") + return + } + + if !c.identicalReplacementLists(n.replacementList, m.repl) && c.ctx.cfg.RejectIncompatibleMacroRedef { + c.err(n.name, "redefinition with different replacement list") + return + } + + if m.variadic != n.variadic && c.ctx.cfg.RejectIncompatibleMacroRedef { + c.err(n.name, "redefinition differs in being variadic") + return + } + } + nms := map[StringID]struct{}{} + for _, v := range n.identifierList { + if _, ok := nms[v.value]; ok { + c.err(v, "duplicate identifier %s", v.value) + } + } + var fp []StringID + for _, v := range n.identifierList { + fp = append(fp, v.value) + } + // dbg("#define %s %s // %v", n.name, tokStr(n.replacementList, " "), c.file.PositionFor(n.name.Pos(), true)) + c.macros[nm] = &Macro{fp: fp, isFnLike: true, name: token4{token3: n.name, file: c.file}, repl: n.replacementList, variadic: n.variadic, namedVariadic: n.namedVariadic} +} + +// [0], 6.10.1 +// +// elif-group: +// # elif constant-expression new-line group_opt +type ppElifGroup struct { + elif *ppElifDirective + groups []ppGroup +} + +func (n *ppElifGroup) evalInclusionCondition(c *cpp) bool { + if !c.evalInclusionCondition(n.elif.expr) { + return false + } + + for _, v := range n.groups { + v.translationPhase4(c) + } + return true +} + +// [0], 6.10.1 +// +// else-group: +// # else new-line group_opt +type ppElseGroup struct { + elseLine *ppElseDirective + groups []ppGroup +} + +func (n *ppElseGroup) translationPhase4(c *cpp) { + if n == nil { + return + } + + for _, v := range n.groups { + v.translationPhase4(c) + } +} + +// [0], 6.10.1 +// +// PreprocessingFile: +// GroupOpt +type ppFile struct { + file *tokenFile + groups []ppGroup +} + +func (n *ppFile) translationPhase4(c *cpp) { + c.ctx.tuSourcesAdd(1) + if f := n.file; f != nil { + c.ctx.tuSizeAdd(int64(f.Size())) + } + for _, v := range n.groups { + v.translationPhase4(c) + } +} + +// [0], 6.10.1 +// +// group-part: +// if-section +// control-line +// text-line +// # non-directive +type ppGroup interface { + translationPhase4(*cpp) +} + +// [0], 6.10.1 +// +// if-group: +// # if constant-expression new-line group opt +// # ifdef identifier new-line group opt +// # ifndef identifier new-line group opt +type ppIfGroup struct { + directive ppIfGroupDirective + groups []ppGroup +} + +func (n *ppIfGroup) evalInclusionCondition(c *cpp) bool { + if !n.directive.evalInclusionCondition(c) { + return false + } + + for _, v := range n.groups { + v.translationPhase4(c) + } + return true +} + +// [0], 6.10.1 +// +// if-section: +// if-group elif-groups_opt else-group_opt endif-line +type ppIfSection struct { + ifGroup *ppIfGroup + elifGroups []*ppElifGroup + elseGroup *ppElseGroup + endifLine *ppEndifDirective +} + +func (n *ppIfSection) translationPhase4(c *cpp) { + if !n.ifGroup.evalInclusionCondition(c) { + for _, v := range n.elifGroups { + if v.evalInclusionCondition(c) { + return + } + } + + n.elseGroup.translationPhase4(c) + } +} diff --git a/vendor/modernc.org/cc/v3/enum.go b/vendor/modernc.org/cc/v3/enum.go new file mode 100644 index 00000000..f93c008d --- /dev/null +++ b/vendor/modernc.org/cc/v3/enum.go @@ -0,0 +1,84 @@ +// 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" + +// Values of Kind +const ( + Invalid Kind = iota + + Array // T[] + Bool // _Bool + Char // char + ComplexChar // complex char + ComplexDouble // complex double + ComplexFloat // complex float + ComplexInt // complex int + ComplexLong // complex long + ComplexLongDouble // complex long double + ComplexLongLong // complex long long + ComplexShort // complex short + ComplexUInt // complex unsigned + ComplexULong // complex unsigned long + ComplexULongLong // complex unsigned long long + ComplexUShort // complex shor + Decimal128 // _Decimal128 + Decimal32 // _Decimal32 + Decimal64 // _Decimal64 + Double // double + Enum // enum + Float // float + Float128 // _Float128 + Float32 // _Float32 + Float32x // _Float32x + Float64 // _Float64 + Float64x // _Float64x + Function // function + Int // int + Int8 // __int8 + Int16 // __int16 + Int32 // __int32 + Int64 // __int64 + Int128 // __int128 + Long // long + LongDouble // long double + LongLong // long long + Ptr // pointer + SChar // signed char + Short // short + Struct // struct + TypedefName // typedefname + UChar // unsigned char + UInt // unsigned + UInt8 // unsigned __int8 + UInt16 // unsigned __int16 + UInt32 // unsigned __int32 + UInt64 // unsigned __int64 + UInt128 // unsigned __int128 + ULong // unsigned long + ULongLong // unsigned long long + UShort // unsigned short + Union // union + Void // void + Vector // vector + + typeofExpr + typeofType + + maxKind +) + +// Values of Linkage +const ( + None Linkage = iota + Internal + External +) + +// Values of StorageClass +const ( + Static StorageClass = iota + Automatic + Allocated +) diff --git a/vendor/modernc.org/cc/v3/filesystem.go b/vendor/modernc.org/cc/v3/filesystem.go new file mode 100644 index 00000000..2a668826 --- /dev/null +++ b/vendor/modernc.org/cc/v3/filesystem.go @@ -0,0 +1,156 @@ +// 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 ( + "io" + "io/ioutil" + "os" + "path" + "strings" + "time" +) + +// Filesystem abstraction used in CC. The underlying value must be comparable (e.g. pointer) to be used in map keys. +type Filesystem interface { + // Stat is an analog of os.Stat, but also accepts a flag to indicate a system include (<file.h>). + Stat(path string, sys bool) (os.FileInfo, error) + // Open is an analog of os.Open, but also accepts a flag to indicate a system include (<file.h>). + Open(path string, sys bool) (io.ReadCloser, error) +} + +// LocalFS returns a local filesystem implementation. +func LocalFS() Filesystem { + return localFS{} +} + +type localFS struct{} + +// Stat implements Filesystem. +func (localFS) Stat(path string, sys bool) (os.FileInfo, error) { + return os.Stat(path) +} + +// Open implements Filesystem. +func (localFS) Open(path string, sys bool) (io.ReadCloser, error) { + return os.Open(path) +} + +// WorkingDir is a filesystem implementation that resolves paths relative to a given directory. +// If filesystem is not specified, the local one will be used. +func WorkingDir(wd string, fs Filesystem) Filesystem { + if fs == nil { + fs = LocalFS() + } + return workDir{fs: fs, wd: wd} +} + +type workDir struct { + fs Filesystem + wd string +} + +// Stat implements Filesystem. +func (fs workDir) Stat(fname string, sys bool) (os.FileInfo, error) { + if !path.IsAbs(fname) { + fname = path.Join(fs.wd, fname) + } + return fs.fs.Stat(fname, sys) +} + +// Open implements Filesystem. +func (fs workDir) Open(fname string, sys bool) (io.ReadCloser, error) { + if !path.IsAbs(fname) { + fname = path.Join(fs.wd, fname) + } + return fs.fs.Open(fname, sys) +} + +// Overlay is a filesystem implementation that first check if the file is available in the primary FS +// and if not, falls back to a secondary FS. +func Overlay(pri, sec Filesystem) Filesystem { + return overlayFS{pri: pri, sec: sec} +} + +type overlayFS struct { + pri, sec Filesystem +} + +// Stat implements Filesystem. +func (fs overlayFS) Stat(path string, sys bool) (os.FileInfo, error) { + st, err := fs.pri.Stat(path, sys) + if err == nil || !os.IsNotExist(err) { + return st, err + } + return fs.sec.Stat(path, sys) +} + +// Open implements Filesystem. +func (fs overlayFS) Open(path string, sys bool) (io.ReadCloser, error) { + f, err := fs.pri.Open(path, sys) + if err == nil || !os.IsNotExist(err) { + return f, err + } + return fs.sec.Open(path, sys) +} + +// StaticFS implements filesystem interface by serving string values form the provided map. +func StaticFS(files map[string]string) Filesystem { + return &staticFS{m: files, ts: time.Now()} +} + +type staticFS struct { + ts time.Time + m map[string]string +} + +// Stat implements Filesystem. +func (fs *staticFS) Stat(path string, sys bool) (os.FileInfo, error) { + v, ok := fs.m[path] + if !ok { + return nil, &os.PathError{"stat", path, os.ErrNotExist} + } + return staticFileInfo{name: path, size: int64(len(v)), mode: 0, mod: fs.ts}, nil +} + +// Open implements Filesystem. +func (fs *staticFS) Open(path string, sys bool) (io.ReadCloser, error) { + v, ok := fs.m[path] + if !ok { + return nil, &os.PathError{"open", path, os.ErrNotExist} + } + return ioutil.NopCloser(strings.NewReader(v)), nil +} + +type staticFileInfo struct { + name string + size int64 + mode os.FileMode + mod time.Time +} + +func (fi staticFileInfo) Name() string { + return fi.name +} + +func (fi staticFileInfo) Size() int64 { + return fi.size +} + +func (fi staticFileInfo) Mode() os.FileMode { + return fi.mode +} + +func (fi staticFileInfo) ModTime() time.Time { + return fi.mod +} + +func (fi staticFileInfo) IsDir() bool { + return fi.mode.IsDir() +} + +func (fi staticFileInfo) Sys() interface{} { + return fi +} diff --git a/vendor/modernc.org/cc/v3/inspect.go b/vendor/modernc.org/cc/v3/inspect.go new file mode 100644 index 00000000..31d44302 --- /dev/null +++ b/vendor/modernc.org/cc/v3/inspect.go @@ -0,0 +1,632 @@ +// Copyright 2020 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" + +// Inspect inspects AST node trees. +// +// If n is a non-terminal node, f(n, true) is called first. Next, f is called +// recursively for each of n's non-nil non-terminal children nodes, if any, in +// alphabetical order. Next, all n's terminal nodes, if any, are visited in +// the numeric order of their suffixes (Token, Token2, Token3, ...). Finally, +// f(n, false) is invoked. +// +// If n a terminal node, of type *Token, f(n, <unspecified boolean value> is +// called once. +// +// Inspect stops when any invocation of f returns false. +func Inspect(n Node, f func(Node, bool) bool) { + see(n, f) +} + +func see(n Node, f func(Node, bool) bool) bool { + switch x := n.(type) { + case *AbstractDeclarator: + return x == nil || f(x, true) && + see(x.DirectAbstractDeclarator, f) && + see(x.Pointer, f) && + f(x, false) + case *AdditiveExpression: + return x == nil || f(x, true) && + see(x.AdditiveExpression, f) && + see(x.MultiplicativeExpression, f) && + see(&x.Token, f) && + f(x, false) + case *AlignmentSpecifier: + return x == nil || f(x, true) && + see(x.ConstantExpression, f) && + see(x.TypeName, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *AndExpression: + return x == nil || f(x, true) && + see(x.AndExpression, f) && + see(x.EqualityExpression, f) && + see(&x.Token, f) && + f(x, false) + case *ArgumentExpressionList: + return x == nil || f(x, true) && + see(x.ArgumentExpressionList, f) && + see(x.AssignmentExpression, f) && + see(&x.Token, f) && + f(x, false) + case *Asm: + return x == nil || f(x, true) && + see(x.AsmArgList, f) && + see(x.AsmQualifierList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + f(x, false) + case *AsmArgList: + return x == nil || f(x, true) && + see(x.AsmArgList, f) && + see(x.AsmExpressionList, f) && + see(&x.Token, f) && + f(x, false) + case *AsmExpressionList: + return x == nil || f(x, true) && + see(x.AsmExpressionList, f) && + see(x.AsmIndex, f) && + see(x.AssignmentExpression, f) && + see(&x.Token, f) && + f(x, false) + case *AsmFunctionDefinition: + return x == nil || f(x, true) && + see(x.AsmStatement, f) && + see(x.DeclarationSpecifiers, f) && + see(x.Declarator, f) && + f(x, false) + case *AsmIndex: + return x == nil || f(x, true) && + see(x.Expression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *AsmQualifier: + return x == nil || f(x, true) && + see(&x.Token, f) && + f(x, false) + case *AsmQualifierList: + return x == nil || f(x, true) && + see(x.AsmQualifier, f) && + see(x.AsmQualifierList, f) && + f(x, false) + case *AsmStatement: + return x == nil || f(x, true) && + see(x.Asm, f) && + see(x.AttributeSpecifierList, f) && + see(&x.Token, f) && + f(x, false) + case *AssignmentExpression: + return x == nil || f(x, true) && + see(x.AssignmentExpression, f) && + see(x.ConditionalExpression, f) && + see(x.UnaryExpression, f) && + see(&x.Token, f) && + f(x, false) + case *AtomicTypeSpecifier: + return x == nil || f(x, true) && + see(x.TypeName, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *AttributeSpecifier: + return x == nil || f(x, true) && + see(x.AttributeValueList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + see(&x.Token5, f) && + f(x, false) + case *AttributeSpecifierList: + return x == nil || f(x, true) && + see(x.AttributeSpecifier, f) && + see(x.AttributeSpecifierList, f) && + f(x, false) + case *AttributeValue: + return x == nil || f(x, true) && + see(x.ExpressionList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *AttributeValueList: + return x == nil || f(x, true) && + see(x.AttributeValue, f) && + see(x.AttributeValueList, f) && + see(&x.Token, f) && + f(x, false) + case *BlockItem: + return x == nil || f(x, true) && + see(x.CompoundStatement, f) && + see(x.Declaration, f) && + see(x.DeclarationSpecifiers, f) && + see(x.Declarator, f) && + see(x.LabelDeclaration, f) && + see(x.PragmaSTDC, f) && + see(x.Statement, f) && + f(x, false) + case *BlockItemList: + return x == nil || f(x, true) && + see(x.BlockItem, f) && + see(x.BlockItemList, f) && + f(x, false) + case *CastExpression: + return x == nil || f(x, true) && + see(x.CastExpression, f) && + see(x.TypeName, f) && + see(x.UnaryExpression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *CompoundStatement: + return x == nil || f(x, true) && + see(x.BlockItemList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *ConditionalExpression: + return x == nil || f(x, true) && + see(x.ConditionalExpression, f) && + see(x.Expression, f) && + see(x.LogicalOrExpression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *ConstantExpression: + return x == nil || f(x, true) && + see(x.ConditionalExpression, f) && + f(x, false) + case *Declaration: + return x == nil || f(x, true) && + see(x.DeclarationSpecifiers, f) && + see(x.InitDeclaratorList, f) && + see(&x.Token, f) && + f(x, false) + case *DeclarationList: + return x == nil || f(x, true) && + see(x.Declaration, f) && + see(x.DeclarationList, f) && + f(x, false) + case *DeclarationSpecifiers: + return x == nil || f(x, true) && + see(x.AlignmentSpecifier, f) && + see(x.AttributeSpecifier, f) && + see(x.DeclarationSpecifiers, f) && + see(x.FunctionSpecifier, f) && + see(x.StorageClassSpecifier, f) && + see(x.TypeQualifier, f) && + see(x.TypeSpecifier, f) && + f(x, false) + case *Declarator: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.DirectDeclarator, f) && + see(x.Pointer, f) && + f(x, false) + case *Designation: + return x == nil || f(x, true) && + see(x.DesignatorList, f) && + see(&x.Token, f) && + f(x, false) + case *Designator: + return x == nil || f(x, true) && + see(x.ConstantExpression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *DesignatorList: + return x == nil || f(x, true) && + see(x.Designator, f) && + see(x.DesignatorList, f) && + f(x, false) + case *DirectAbstractDeclarator: + return x == nil || f(x, true) && + see(x.AbstractDeclarator, f) && + see(x.AssignmentExpression, f) && + see(x.DirectAbstractDeclarator, f) && + see(x.ParameterTypeList, f) && + see(x.TypeQualifiers, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *DirectDeclarator: + return x == nil || f(x, true) && + see(x.Asm, f) && + see(x.AssignmentExpression, f) && + see(x.AttributeSpecifierList, f) && + see(x.Declarator, f) && + see(x.DirectDeclarator, f) && + see(x.IdentifierList, f) && + see(x.ParameterTypeList, f) && + see(x.TypeQualifiers, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *EnumSpecifier: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.EnumeratorList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + see(&x.Token5, f) && + f(x, false) + case *Enumerator: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.ConstantExpression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *EnumeratorList: + return x == nil || f(x, true) && + see(x.Enumerator, f) && + see(x.EnumeratorList, f) && + see(&x.Token, f) && + f(x, false) + case *EqualityExpression: + return x == nil || f(x, true) && + see(x.EqualityExpression, f) && + see(x.RelationalExpression, f) && + see(&x.Token, f) && + f(x, false) + case *ExclusiveOrExpression: + return x == nil || f(x, true) && + see(x.AndExpression, f) && + see(x.ExclusiveOrExpression, f) && + see(&x.Token, f) && + f(x, false) + case *Expression: + return x == nil || f(x, true) && + see(x.AssignmentExpression, f) && + see(x.Expression, f) && + see(&x.Token, f) && + f(x, false) + case *ExpressionList: + return x == nil || f(x, true) && + see(x.AssignmentExpression, f) && + see(x.ExpressionList, f) && + see(&x.Token, f) && + f(x, false) + case *ExpressionStatement: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.Expression, f) && + see(&x.Token, f) && + f(x, false) + case *ExternalDeclaration: + return x == nil || f(x, true) && + see(x.AsmFunctionDefinition, f) && + see(x.AsmStatement, f) && + see(x.Declaration, f) && + see(x.FunctionDefinition, f) && + see(x.PragmaSTDC, f) && + see(&x.Token, f) && + f(x, false) + case *FunctionDefinition: + return x == nil || f(x, true) && + see(x.CompoundStatement, f) && + see(x.DeclarationList, f) && + see(x.DeclarationSpecifiers, f) && + see(x.Declarator, f) && + f(x, false) + case *FunctionSpecifier: + return x == nil || f(x, true) && + see(&x.Token, f) && + f(x, false) + case *IdentifierList: + return x == nil || f(x, true) && + see(x.IdentifierList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *InclusiveOrExpression: + return x == nil || f(x, true) && + see(x.ExclusiveOrExpression, f) && + see(x.InclusiveOrExpression, f) && + see(&x.Token, f) && + f(x, false) + case *InitDeclarator: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.Declarator, f) && + see(x.Initializer, f) && + see(&x.Token, f) && + f(x, false) + case *InitDeclaratorList: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.InitDeclarator, f) && + see(x.InitDeclaratorList, f) && + see(&x.Token, f) && + f(x, false) + case *Initializer: + return x == nil || f(x, true) && + see(x.AssignmentExpression, f) && + see(x.InitializerList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *InitializerList: + return x == nil || f(x, true) && + see(x.Designation, f) && + see(x.Initializer, f) && + see(x.InitializerList, f) && + see(&x.Token, f) && + f(x, false) + case *IterationStatement: + return x == nil || f(x, true) && + see(x.Declaration, f) && + see(x.Expression, f) && + see(x.Expression2, f) && + see(x.Expression3, f) && + see(x.Statement, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + see(&x.Token5, f) && + f(x, false) + case *JumpStatement: + return x == nil || f(x, true) && + see(x.Expression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *LabelDeclaration: + return x == nil || f(x, true) && + see(x.IdentifierList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *LabeledStatement: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.ConstantExpression, f) && + see(x.ConstantExpression2, f) && + see(x.Statement, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *LogicalAndExpression: + return x == nil || f(x, true) && + see(x.InclusiveOrExpression, f) && + see(x.LogicalAndExpression, f) && + see(&x.Token, f) && + f(x, false) + case *LogicalOrExpression: + return x == nil || f(x, true) && + see(x.LogicalAndExpression, f) && + see(x.LogicalOrExpression, f) && + see(&x.Token, f) && + f(x, false) + case *MultiplicativeExpression: + return x == nil || f(x, true) && + see(x.CastExpression, f) && + see(x.MultiplicativeExpression, f) && + see(&x.Token, f) && + f(x, false) + case *ParameterDeclaration: + return x == nil || f(x, true) && + see(x.AbstractDeclarator, f) && + see(x.AttributeSpecifierList, f) && + see(x.DeclarationSpecifiers, f) && + see(x.Declarator, f) && + f(x, false) + case *ParameterList: + return x == nil || f(x, true) && + see(x.ParameterDeclaration, f) && + see(x.ParameterList, f) && + see(&x.Token, f) && + f(x, false) + case *ParameterTypeList: + return x == nil || f(x, true) && + see(x.ParameterList, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *Pointer: + return x == nil || f(x, true) && + see(x.Pointer, f) && + see(x.TypeQualifiers, f) && + see(&x.Token, f) && + f(x, false) + case *PostfixExpression: + return x == nil || f(x, true) && + see(x.ArgumentExpressionList, f) && + see(x.Expression, f) && + see(x.InitializerList, f) && + see(x.PostfixExpression, f) && + see(x.PrimaryExpression, f) && + see(x.TypeName, f) && + see(x.TypeName2, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + see(&x.Token5, f) && + f(x, false) + case *PragmaSTDC: + return x == nil || f(x, true) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + f(x, false) + case *PrimaryExpression: + return x == nil || f(x, true) && + see(x.CompoundStatement, f) && + see(x.Expression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + f(x, false) + case *RelationalExpression: + return x == nil || f(x, true) && + see(x.RelationalExpression, f) && + see(x.ShiftExpression, f) && + see(&x.Token, f) && + f(x, false) + case *SelectionStatement: + return x == nil || f(x, true) && + see(x.Expression, f) && + see(x.Statement, f) && + see(x.Statement2, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + see(&x.Token4, f) && + f(x, false) + case *ShiftExpression: + return x == nil || f(x, true) && + see(x.AdditiveExpression, f) && + see(x.ShiftExpression, f) && + see(&x.Token, f) && + f(x, false) + case *SpecifierQualifierList: + return x == nil || f(x, true) && + see(x.AlignmentSpecifier, f) && + see(x.AttributeSpecifier, f) && + see(x.SpecifierQualifierList, f) && + see(x.TypeQualifier, f) && + see(x.TypeSpecifier, f) && + f(x, false) + case *Statement: + return x == nil || f(x, true) && + see(x.AsmStatement, f) && + see(x.CompoundStatement, f) && + see(x.ExpressionStatement, f) && + see(x.IterationStatement, f) && + see(x.JumpStatement, f) && + see(x.LabeledStatement, f) && + see(x.SelectionStatement, f) && + f(x, false) + case *StorageClassSpecifier: + return x == nil || f(x, true) && + see(&x.Token, f) && + f(x, false) + case *StructDeclaration: + return x == nil || f(x, true) && + see(x.SpecifierQualifierList, f) && + see(x.StructDeclaratorList, f) && + see(&x.Token, f) && + f(x, false) + case *StructDeclarationList: + return x == nil || f(x, true) && + see(x.StructDeclaration, f) && + see(x.StructDeclarationList, f) && + f(x, false) + case *StructDeclarator: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.ConstantExpression, f) && + see(x.Declarator, f) && + see(&x.Token, f) && + f(x, false) + case *StructDeclaratorList: + return x == nil || f(x, true) && + see(x.StructDeclarator, f) && + see(x.StructDeclaratorList, f) && + see(&x.Token, f) && + f(x, false) + case *StructOrUnion: + return x == nil || f(x, true) && + see(&x.Token, f) && + f(x, false) + case *StructOrUnionSpecifier: + return x == nil || f(x, true) && + see(x.AttributeSpecifierList, f) && + see(x.StructDeclarationList, f) && + see(x.StructOrUnion, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *TranslationUnit: + return x == nil || f(x, true) && + see(x.ExternalDeclaration, f) && + see(x.TranslationUnit, f) && + f(x, false) + case *TypeName: + return x == nil || f(x, true) && + see(x.AbstractDeclarator, f) && + see(x.SpecifierQualifierList, f) && + f(x, false) + case *TypeQualifier: + return x == nil || f(x, true) && + see(&x.Token, f) && + f(x, false) + case *TypeQualifiers: + return x == nil || f(x, true) && + see(x.AttributeSpecifier, f) && + see(x.TypeQualifier, f) && + see(x.TypeQualifiers, f) && + f(x, false) + case *TypeSpecifier: + return x == nil || f(x, true) && + see(x.AtomicTypeSpecifier, f) && + see(x.EnumSpecifier, f) && + see(x.Expression, f) && + see(x.StructOrUnionSpecifier, f) && + see(x.TypeName, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *UnaryExpression: + return x == nil || f(x, true) && + see(x.CastExpression, f) && + see(x.PostfixExpression, f) && + see(x.TypeName, f) && + see(x.UnaryExpression, f) && + see(&x.Token, f) && + see(&x.Token2, f) && + see(&x.Token2, f) && + see(&x.Token3, f) && + f(x, false) + case *Token: + return f(x, true) + default: + panic(todo("internal error: %T", x)) + } +} diff --git a/vendor/modernc.org/cc/v3/lexer.go b/vendor/modernc.org/cc/v3/lexer.go new file mode 100644 index 00000000..d1366135 --- /dev/null +++ b/vendor/modernc.org/cc/v3/lexer.go @@ -0,0 +1,1555 @@ +// Code generated by golex. DO NOT EDIT. + +// 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" + +func (s *scanner) scan() (r rune) { + +yystate0: + yyrule := -1 + _ = yyrule + c := s.initScan() + + goto yystart1 + +yyAction: + switch yyrule { + case 1: + goto yyrule1 + case 2: + goto yyrule2 + case 3: + goto yyrule3 + case 4: + goto yyrule4 + case 5: + goto yyrule5 + case 6: + goto yyrule6 + case 7: + goto yyrule7 + case 8: + goto yyrule8 + case 9: + goto yyrule9 + case 10: + goto yyrule10 + case 11: + goto yyrule11 + case 12: + goto yyrule12 + case 13: + goto yyrule13 + case 14: + goto yyrule14 + case 15: + goto yyrule15 + case 16: + goto yyrule16 + case 17: + goto yyrule17 + case 18: + goto yyrule18 + case 19: + goto yyrule19 + case 20: + goto yyrule20 + case 21: + goto yyrule21 + case 22: + goto yyrule22 + case 23: + goto yyrule23 + case 24: + goto yyrule24 + case 25: + goto yyrule25 + case 26: + goto yyrule26 + case 27: + goto yyrule27 + case 28: + goto yyrule28 + case 29: + goto yyrule29 + case 30: + goto yyrule30 + case 31: + goto yyrule31 + case 32: + goto yyrule32 + case 33: + goto yyrule33 + case 34: + goto yyrule34 + case 35: + goto yyrule35 + case 36: + goto yyrule36 + case 37: + goto yyrule37 + case 38: + goto yyrule38 + case 39: + goto yyrule39 + } +yystate1: + c = s.next() +yystart1: + switch { + default: + goto yyabort + case c == '!': + goto yystate16 + case c == '"': + goto yystate18 + case c == '#': + goto yystate29 + case c == '$' || c >= 'A' && c <= 'K' || c >= 'M' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c == '\u0081': + goto yystate31 + case c == '%': + goto yystate41 + case c == '&': + goto yystate47 + case c == '*': + goto yystate62 + case c == '+': + goto yystate64 + case c == '-': + goto yystate67 + case c == '.': + goto yystate71 + case c == '/': + goto yystate85 + case c == ':': + goto yystate88 + case c == '<': + goto yystate90 + case c == '=': + goto yystate96 + case c == '>': + goto yystate98 + case c == 'L': + goto yystate102 + case c == '\'': + goto yystate50 + case c == '\\': + goto yystate32 + case c == '\n': + goto yystate14 + case c == '\r': + goto yystate15 + case c == '\t' || c == '\v' || c == '\f' || c == ' ': + goto yystate2 + case c == '^': + goto yystate126 + case c == '|': + goto yystate128 + case c >= '0' && c <= '9': + goto yystate74 + } + +yystate2: + c = s.next() + yyrule = 2 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule2 + case c == '/': + goto yystate3 + case c == '\t' || c == '\v' || c == '\f' || c == ' ': + goto yystate2 + } + +yystate3: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate4 + case c == '/': + goto yystate13 + } + +yystate4: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate6 + case c == '\n': + goto yystate5 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= ')' || c >= '+' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate4 + } + +yystate5: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate6 + case c == '\n': + goto yystate5 + case c == '\u0080': + goto yystate7 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= ')' || c >= '+' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate4 + } + +yystate6: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate6 + case c == '/': + goto yystate2 + case c == '\n': + goto yystate5 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= ')' || c >= '+' && c <= '.' || c >= '0' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate4 + } + +yystate7: + c = s.next() + yyrule = 3 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule3 + case c == '/': + goto yystate9 + case c == '\t' || c == '\v' || c == '\f' || c == ' ': + goto yystate8 + } + +yystate8: + c = s.next() + switch { + default: + goto yyabort + case c == '/': + goto yystate9 + case c == '\t' || c == '\v' || c == '\f' || c == ' ': + goto yystate8 + } + +yystate9: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate10 + } + +yystate10: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate12 + case c == '\n': + goto yystate11 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= ')' || c >= '+' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate10 + } + +yystate11: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate12 + case c == '\n': + goto yystate11 + case c == '\u0080': + goto yystate7 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= ')' || c >= '+' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate10 + } + +yystate12: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate12 + case c == '/': + goto yystate8 + case c == '\n': + goto yystate11 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= ')' || c >= '+' && c <= '.' || c >= '0' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate10 + } + +yystate13: + c = s.next() + yyrule = 1 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule1 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate13 + } + +yystate14: + c = s.next() + yyrule = 39 + s.mark = len(s.charBuf) + goto yyrule39 + +yystate15: + c = s.next() + switch { + default: + goto yyabort + case c == '\n': + goto yystate14 + } + +yystate16: + c = s.next() + switch { + default: + goto yyabort + case c == '=': + goto yystate17 + } + +yystate17: + c = s.next() + yyrule = 4 + s.mark = len(s.charBuf) + goto yyrule4 + +yystate18: + c = s.next() + switch { + default: + goto yyabort + case c == '"': + goto yystate19 + case c == '\\': + goto yystate20 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '!' || c >= '#' && c <= '[' || c >= ']' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate18 + } + +yystate19: + c = s.next() + yyrule = 38 + s.mark = len(s.charBuf) + goto yyrule38 + +yystate20: + c = s.next() + switch { + default: + goto yyabort + case c == '"' || c == '\'' || c >= '0' && c <= '7' || c == '?' || c == '\\' || c == 'a' || c == 'b' || c == 'e' || c == 'f' || c == 'n' || c == 'r' || c == 't' || c == 'v': + goto yystate18 + case c == 'U': + goto yystate21 + case c == 'u': + goto yystate25 + case c == 'x': + goto yystate28 + } + +yystate21: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate22 + } + +yystate22: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate23 + } + +yystate23: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate24 + } + +yystate24: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate25 + } + +yystate25: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate26 + } + +yystate26: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate27 + } + +yystate27: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate28 + } + +yystate28: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate18 + } + +yystate29: + c = s.next() + switch { + default: + goto yyabort + case c == '#': + goto yystate30 + } + +yystate30: + c = s.next() + yyrule = 5 + s.mark = len(s.charBuf) + goto yyrule5 + +yystate31: + c = s.next() + yyrule = 36 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule36 + case c == '$' || c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c == '\u0081': + goto yystate31 + case c == '\\': + goto yystate32 + } + +yystate32: + c = s.next() + switch { + default: + goto yyabort + case c == 'U': + goto yystate33 + case c == 'u': + goto yystate37 + } + +yystate33: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate34 + } + +yystate34: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate35 + } + +yystate35: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate36 + } + +yystate36: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate37 + } + +yystate37: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate38 + } + +yystate38: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate39 + } + +yystate39: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate40 + } + +yystate40: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate31 + } + +yystate41: + c = s.next() + switch { + default: + goto yyabort + case c == ':': + goto yystate42 + case c == '=': + goto yystate45 + case c == '>': + goto yystate46 + } + +yystate42: + c = s.next() + yyrule = 6 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule6 + case c == '%': + goto yystate43 + } + +yystate43: + c = s.next() + switch { + default: + goto yyabort + case c == ':': + goto yystate44 + } + +yystate44: + c = s.next() + yyrule = 7 + s.mark = len(s.charBuf) + goto yyrule7 + +yystate45: + c = s.next() + yyrule = 8 + s.mark = len(s.charBuf) + goto yyrule8 + +yystate46: + c = s.next() + yyrule = 9 + s.mark = len(s.charBuf) + goto yyrule9 + +yystate47: + c = s.next() + switch { + default: + goto yyabort + case c == '&': + goto yystate48 + case c == '=': + goto yystate49 + } + +yystate48: + c = s.next() + yyrule = 10 + s.mark = len(s.charBuf) + goto yyrule10 + +yystate49: + c = s.next() + yyrule = 11 + s.mark = len(s.charBuf) + goto yyrule11 + +yystate50: + c = s.next() + switch { + default: + goto yyabort + case c == '\\': + goto yystate53 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '&' || c >= '(' && c <= '[' || c >= ']' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate51 + } + +yystate51: + c = s.next() + switch { + default: + goto yyabort + case c == '\'': + goto yystate52 + case c == '\\': + goto yystate53 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '&' || c >= '(' && c <= '[' || c >= ']' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate51 + } + +yystate52: + c = s.next() + yyrule = 35 + s.mark = len(s.charBuf) + goto yyrule35 + +yystate53: + c = s.next() + switch { + default: + goto yyabort + case c == '"' || c == '\'' || c >= '0' && c <= '7' || c == '?' || c == '\\' || c == 'a' || c == 'b' || c == 'e' || c == 'f' || c == 'n' || c == 'r' || c == 't' || c == 'v': + goto yystate51 + case c == 'U': + goto yystate54 + case c == 'u': + goto yystate58 + case c == 'x': + goto yystate61 + } + +yystate54: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate55 + } + +yystate55: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate56 + } + +yystate56: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate57 + } + +yystate57: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate58 + } + +yystate58: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate59 + } + +yystate59: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate60 + } + +yystate60: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate61 + } + +yystate61: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate51 + } + +yystate62: + c = s.next() + switch { + default: + goto yyabort + case c == '=': + goto yystate63 + } + +yystate63: + c = s.next() + yyrule = 12 + s.mark = len(s.charBuf) + goto yyrule12 + +yystate64: + c = s.next() + switch { + default: + goto yyabort + case c == '+': + goto yystate65 + case c == '=': + goto yystate66 + } + +yystate65: + c = s.next() + yyrule = 13 + s.mark = len(s.charBuf) + goto yyrule13 + +yystate66: + c = s.next() + yyrule = 14 + s.mark = len(s.charBuf) + goto yyrule14 + +yystate67: + c = s.next() + switch { + default: + goto yyabort + case c == '-': + goto yystate68 + case c == '=': + goto yystate69 + case c == '>': + goto yystate70 + } + +yystate68: + c = s.next() + yyrule = 15 + s.mark = len(s.charBuf) + goto yyrule15 + +yystate69: + c = s.next() + yyrule = 16 + s.mark = len(s.charBuf) + goto yyrule16 + +yystate70: + c = s.next() + yyrule = 17 + s.mark = len(s.charBuf) + goto yyrule17 + +yystate71: + c = s.next() + switch { + default: + goto yyabort + case c == '.': + goto yystate72 + case c >= '0' && c <= '9': + goto yystate74 + } + +yystate72: + c = s.next() + switch { + default: + goto yyabort + case c == '.': + goto yystate73 + } + +yystate73: + c = s.next() + yyrule = 18 + s.mark = len(s.charBuf) + goto yyrule18 + +yystate74: + c = s.next() + yyrule = 37 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule37 + case c == '$' || c == '.' || c >= '0' && c <= '9' || c >= 'A' && c <= 'D' || c >= 'F' && c <= 'O' || c >= 'Q' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'o' || c >= 'q' && c <= 'z' || c == '\u0081': + goto yystate74 + case c == 'E' || c == 'P' || c == 'e' || c == 'p': + goto yystate75 + case c == '\\': + goto yystate76 + } + +yystate75: + c = s.next() + yyrule = 37 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule37 + case c == '$' || c == '+' || c == '-' || c == '.' || c >= '0' && c <= '9' || c >= 'A' && c <= 'D' || c >= 'F' && c <= 'O' || c >= 'Q' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'd' || c >= 'f' && c <= 'o' || c >= 'q' && c <= 'z' || c == '\u0081': + goto yystate74 + case c == 'E' || c == 'P' || c == 'e' || c == 'p': + goto yystate75 + case c == '\\': + goto yystate76 + } + +yystate76: + c = s.next() + switch { + default: + goto yyabort + case c == 'U': + goto yystate77 + case c == 'u': + goto yystate81 + } + +yystate77: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate78 + } + +yystate78: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate79 + } + +yystate79: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate80 + } + +yystate80: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate81 + } + +yystate81: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate82 + } + +yystate82: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate83 + } + +yystate83: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate84 + } + +yystate84: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate74 + } + +yystate85: + c = s.next() + switch { + default: + goto yyabort + case c == '*': + goto yystate4 + case c == '/': + goto yystate86 + case c == '=': + goto yystate87 + } + +yystate86: + c = s.next() + yyrule = 1 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule1 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate86 + } + +yystate87: + c = s.next() + yyrule = 19 + s.mark = len(s.charBuf) + goto yyrule19 + +yystate88: + c = s.next() + switch { + default: + goto yyabort + case c == '>': + goto yystate89 + } + +yystate89: + c = s.next() + yyrule = 20 + s.mark = len(s.charBuf) + goto yyrule20 + +yystate90: + c = s.next() + switch { + default: + goto yyabort + case c == '%': + goto yystate91 + case c == ':': + goto yystate92 + case c == '<': + goto yystate93 + case c == '=': + goto yystate95 + } + +yystate91: + c = s.next() + yyrule = 21 + s.mark = len(s.charBuf) + goto yyrule21 + +yystate92: + c = s.next() + yyrule = 22 + s.mark = len(s.charBuf) + goto yyrule22 + +yystate93: + c = s.next() + yyrule = 23 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule23 + case c == '=': + goto yystate94 + } + +yystate94: + c = s.next() + yyrule = 24 + s.mark = len(s.charBuf) + goto yyrule24 + +yystate95: + c = s.next() + yyrule = 25 + s.mark = len(s.charBuf) + goto yyrule25 + +yystate96: + c = s.next() + switch { + default: + goto yyabort + case c == '=': + goto yystate97 + } + +yystate97: + c = s.next() + yyrule = 26 + s.mark = len(s.charBuf) + goto yyrule26 + +yystate98: + c = s.next() + switch { + default: + goto yyabort + case c == '=': + goto yystate99 + case c == '>': + goto yystate100 + } + +yystate99: + c = s.next() + yyrule = 27 + s.mark = len(s.charBuf) + goto yyrule27 + +yystate100: + c = s.next() + yyrule = 28 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule28 + case c == '=': + goto yystate101 + } + +yystate101: + c = s.next() + yyrule = 29 + s.mark = len(s.charBuf) + goto yyrule29 + +yystate102: + c = s.next() + yyrule = 36 + s.mark = len(s.charBuf) + switch { + default: + goto yyrule36 + case c == '"': + goto yystate103 + case c == '$' || c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c == '\u0081': + goto yystate31 + case c == '\'': + goto yystate114 + case c == '\\': + goto yystate32 + } + +yystate103: + c = s.next() + switch { + default: + goto yyabort + case c == '"': + goto yystate104 + case c == '\\': + goto yystate105 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '!' || c >= '#' && c <= '[' || c >= ']' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate103 + } + +yystate104: + c = s.next() + yyrule = 33 + s.mark = len(s.charBuf) + goto yyrule33 + +yystate105: + c = s.next() + switch { + default: + goto yyabort + case c == '"' || c == '\'' || c >= '0' && c <= '7' || c == '?' || c == '\\' || c == 'a' || c == 'b' || c == 'e' || c == 'f' || c == 'n' || c == 'r' || c == 't' || c == 'v': + goto yystate103 + case c == 'U': + goto yystate106 + case c == 'u': + goto yystate110 + case c == 'x': + goto yystate113 + } + +yystate106: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate107 + } + +yystate107: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate108 + } + +yystate108: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate109 + } + +yystate109: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate110 + } + +yystate110: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate111 + } + +yystate111: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate112 + } + +yystate112: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate113 + } + +yystate113: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate103 + } + +yystate114: + c = s.next() + switch { + default: + goto yyabort + case c == '\\': + goto yystate117 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '&' || c >= '(' && c <= '[' || c >= ']' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate115 + } + +yystate115: + c = s.next() + switch { + default: + goto yyabort + case c == '\'': + goto yystate116 + case c == '\\': + goto yystate117 + case c >= '\x01' && c <= '\t' || c >= '\v' && c <= '&' || c >= '(' && c <= '[' || c >= ']' && c <= '\u007f' || c >= '\u0081' && c <= 'ÿ': + goto yystate115 + } + +yystate116: + c = s.next() + yyrule = 34 + s.mark = len(s.charBuf) + goto yyrule34 + +yystate117: + c = s.next() + switch { + default: + goto yyabort + case c == '"' || c == '\'' || c >= '0' && c <= '7' || c == '?' || c == '\\' || c == 'a' || c == 'b' || c == 'e' || c == 'f' || c == 'n' || c == 'r' || c == 't' || c == 'v': + goto yystate115 + case c == 'U': + goto yystate118 + case c == 'u': + goto yystate122 + case c == 'x': + goto yystate125 + } + +yystate118: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate119 + } + +yystate119: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate120 + } + +yystate120: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate121 + } + +yystate121: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate122 + } + +yystate122: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate123 + } + +yystate123: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate124 + } + +yystate124: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate125 + } + +yystate125: + c = s.next() + switch { + default: + goto yyabort + case c >= '0' && c <= '9' || c >= 'A' && c <= 'F' || c >= 'a' && c <= 'f': + goto yystate115 + } + +yystate126: + c = s.next() + switch { + default: + goto yyabort + case c == '=': + goto yystate127 + } + +yystate127: + c = s.next() + yyrule = 30 + s.mark = len(s.charBuf) + goto yyrule30 + +yystate128: + c = s.next() + switch { + default: + goto yyabort + case c == '=': + goto yystate129 + case c == '|': + goto yystate130 + } + +yystate129: + c = s.next() + yyrule = 31 + s.mark = len(s.charBuf) + goto yyrule31 + +yystate130: + c = s.next() + yyrule = 32 + s.mark = len(s.charBuf) + goto yyrule32 + +yyrule1: // ({white-space}|{comment})*{line-comment} +yyrule2: // ({white-space}|{comment})+{line-comment}? + { + + return ' ' + } +yyrule3: // (({white-space}|{comment})*{comment-not-terminated})+ + { + + return s.unterminatedComment() + } +yyrule4: // "!=" + { + return NEQ + } +yyrule5: // "##" + { + return PPPASTE + } +yyrule6: // "%:" + { + return '#' + } +yyrule7: // "%:%:" + { + return PPPASTE + } +yyrule8: // "%=" + { + return MODASSIGN + } +yyrule9: // "%>" + { + return '}' + } +yyrule10: // "&&" + { + return ANDAND + } +yyrule11: // "&=" + { + return ANDASSIGN + } +yyrule12: // "*=" + { + return MULASSIGN + } +yyrule13: // "++" + { + return INC + } +yyrule14: // "+=" + { + return ADDASSIGN + } +yyrule15: // "--" + { + return DEC + } +yyrule16: // "-=" + { + return SUBASSIGN + } +yyrule17: // "->" + { + return ARROW + } +yyrule18: // "..." + { + return DDD + } +yyrule19: // "/=" + { + return DIVASSIGN + } +yyrule20: // ":>" + { + return ']' + } +yyrule21: // "<%" + { + return '{' + } +yyrule22: // "<:" + { + return '[' + } +yyrule23: // "<<" + { + return LSH + } +yyrule24: // "<<=" + { + return LSHASSIGN + } +yyrule25: // "<=" + { + return LEQ + } +yyrule26: // "==" + { + return EQ + } +yyrule27: // ">=" + { + return GEQ + } +yyrule28: // ">>" + { + return RSH + } +yyrule29: // ">>=" + { + return RSHASSIGN + } +yyrule30: // "^=" + { + return XORASSIGN + } +yyrule31: // "|=" + { + return ORASSIGN + } +yyrule32: // "||" + { + return OROR + } +yyrule33: // L{string-literal} + { + return LONGSTRINGLITERAL + } +yyrule34: // L{character-constant} + { + return LONGCHARCONST + } +yyrule35: // {character-constant} + { + return CHARCONST + } +yyrule36: // {identifier} + { + return IDENTIFIER + } +yyrule37: // {pp-number} + { + return PPNUMBER + } +yyrule38: // {string-literal} + { + return STRINGLITERAL + } +yyrule39: // \r?\n + if true { // avoid go vet determining the below panic will not be reached + return '\n' + } + panic("unreachable") + +yyabort: // no lexem recognized + // + // silence unused label errors for build and satisfy go vet reachability analysis + // + { + if false { + goto yyabort + } + if false { + goto yystate0 + } + if false { + goto yystate1 + } + } + + if c, ok := s.abort(); ok { + return rune(c) + } + + goto yyAction +} diff --git a/vendor/modernc.org/cc/v3/lexer.l b/vendor/modernc.org/cc/v3/lexer.l new file mode 100644 index 00000000..4a2bf53a --- /dev/null +++ b/vendor/modernc.org/cc/v3/lexer.l @@ -0,0 +1,97 @@ +%{ +// 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. +%} + +%yyc c +%yyn c = s.next() +%yym s.mark = len(s.charBuf) + +%{ +package cc // import "modernc.org/cc/v3" + +func (s *scanner) scan() (r rune) { +%} + +c-char [^'\n\x80\\]|{escape-sequence} +c-char-sequence {c-char}+ +character-constant '{c-char-sequence}' +comment "/*"([^*\x80]|\*+[^*/\x80])*\*+\/ +comment-not-terminated "/*"([^*\x80]|\*+[^*/\x80])*(\*+)?\n\x80 +digit [0-9] +escape-sequence {simple-sequence}|{octal-escape-sequence}|{hexadecimal-escape-sequence}|{universal-character-name} +hex-quad {hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit}{hexadecimal-digit} +hexadecimal-digit [0-9a-fA-F] +hexadecimal-escape-sequence \\x{hexadecimal-digit}+ +identifier {identifier-nondigit}({identifier-nondigit}|{digit}|"$")* +identifier-nondigit {nondigit}|"$"|{universal-character-name} +line-comment "//"[^\n\x80]* +nondigit [_a-zA-Z\x81] +octal-digit [0-7] +octal-escape-sequence \\{octal-digit}{octal-digit}?{octal-digit}? +pp-number ({digit}|\.{digit})({digit}|{identifier-nondigit}|[eEpP]{sign}|\.)* +s-char [^\x22\n\x80\\]|{escape-sequence} +s-char-sequence {s-char}+ +sign [-+] +simple-sequence \\['\x22?\\abefnrtv] +string-literal \x22{s-char-sequence}?\x22 +universal-character-name \\u{hex-quad}|\\U{hex-quad}{hex-quad} +white-space [ \t\f\v] + +%% + c := s.initScan() + +({white-space}|{comment})*{line-comment} | +({white-space}|{comment})+{line-comment}? + return ' ' + +(({white-space}|{comment})*{comment-not-terminated})+ + return s.unterminatedComment() + +"!=" return NEQ +"##" return PPPASTE +"%:" return '#' +"%:%:" return PPPASTE +"%=" return MODASSIGN +"%>" return '}' +"&&" return ANDAND +"&=" return ANDASSIGN +"*=" return MULASSIGN +"++" return INC +"+=" return ADDASSIGN +"--" return DEC +"-=" return SUBASSIGN +"->" return ARROW +"..." return DDD +"/=" return DIVASSIGN +":>" return ']' +"<%" return '{' +"<:" return '[' +"<<" return LSH +"<<=" return LSHASSIGN +"<=" return LEQ +"==" return EQ +">=" return GEQ +">>" return RSH +">>=" return RSHASSIGN +"^=" return XORASSIGN +"|=" return ORASSIGN +"||" return OROR + +L{string-literal} return LONGSTRINGLITERAL +L{character-constant} return LONGCHARCONST +{character-constant} return CHARCONST +{identifier} return IDENTIFIER +{pp-number} return PPNUMBER +{string-literal} return STRINGLITERAL + +\r?\n return '\n' + +%% + if c, ok := s.abort(); ok { + return rune(c) + } + + goto yyAction +} diff --git a/vendor/modernc.org/cc/v3/operand.go b/vendor/modernc.org/cc/v3/operand.go new file mode 100644 index 00000000..24c46616 --- /dev/null +++ b/vendor/modernc.org/cc/v3/operand.go @@ -0,0 +1,1337 @@ +// 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" + "math" + "math/big" +) + +var ( + _ Value = (*Float128Value)(nil) + _ Value = (*InitializerValue)(nil) + _ Value = Complex128Value(0) + _ Value = Complex256Value{} + _ Value = Complex64Value(0) + _ Value = Float32Value(0) + _ Value = Float64Value(0) + _ Value = Int64Value(0) + _ Value = StringValue(0) + _ Value = Uint64Value(0) + _ Value = WideStringValue(0) + + _ Operand = (*funcDesignator)(nil) + _ Operand = (*lvalue)(nil) + _ Operand = (*operand)(nil) + _ Operand = noOperand + + noOperand = &operand{typ: noType} +) + +type Operand interface { + // IsAssingmentCompatible reports whether the operand can be + // assigned to lhs. [0], 6.5.16.1. + IsAssingmentCompatible(lhs Type) bool + ConvertTo(Type) Operand + Declarator() *Declarator + IsConst() bool + IsLValue() bool + IsNonZero() bool + IsZero() bool + Offset() uintptr // Valid only for non nil Declarator() value + Type() Type + Value() Value + convertFromInt(*context, Node, Type) Operand + convertTo(*context, Node, Type) Operand + convertToInt(*context, Node, Type) Operand + getABI() *ABI + integerPromotion(*context, Node) Operand + normalize(*context, Node) Operand +} + +type Value interface { + IsConst() bool + IsNonZero() bool + IsZero() bool + add(b Value) Value + and(b Value) Value + cpl() Value + div(b Value) Value + eq(b Value) Value + ge(b Value) Value + gt(b Value) Value + le(b Value) Value + lsh(b Value) Value + lt(b Value) Value + mod(b Value) Value + mul(b Value) Value + neg() Value + neq(b Value) Value + or(b Value) Value + rsh(b Value) Value + sub(b Value) Value + xor(b Value) Value +} + +type WideStringValue StringID + +func (v WideStringValue) add(b Value) Value { panic(todo("")) } +func (v WideStringValue) and(b Value) Value { panic(todo("")) } +func (v WideStringValue) cpl() Value { panic(todo("")) } +func (v WideStringValue) div(b Value) Value { panic(todo("")) } +func (v WideStringValue) eq(b Value) Value { return boolValue(v == b.(WideStringValue)) } +func (v WideStringValue) IsConst() bool { return true } +func (v WideStringValue) IsNonZero() bool { return true } +func (v WideStringValue) IsZero() bool { return false } +func (v WideStringValue) lsh(b Value) Value { panic(todo("")) } +func (v WideStringValue) mod(b Value) Value { panic(todo("")) } +func (v WideStringValue) mul(b Value) Value { panic(todo("")) } +func (v WideStringValue) neg() Value { panic(todo("")) } +func (v WideStringValue) neq(b Value) Value { return boolValue(v != b.(WideStringValue)) } +func (v WideStringValue) or(b Value) Value { panic(todo("")) } +func (v WideStringValue) rsh(b Value) Value { panic(todo("")) } +func (v WideStringValue) sub(b Value) Value { panic(todo("")) } +func (v WideStringValue) xor(b Value) Value { panic(todo("")) } + +func (v WideStringValue) le(b Value) Value { + return boolValue(StringID(v).String() <= StringID(b.(WideStringValue)).String()) +} + +func (v WideStringValue) ge(b Value) Value { + return boolValue(StringID(v).String() >= StringID(b.(WideStringValue)).String()) +} + +func (v WideStringValue) gt(b Value) Value { + return boolValue(StringID(v).String() > StringID(b.(WideStringValue)).String()) +} + +func (v WideStringValue) lt(b Value) Value { + return boolValue(StringID(v).String() < StringID(b.(WideStringValue)).String()) +} + +type StringValue StringID + +func (v StringValue) add(b Value) Value { panic(todo("")) } +func (v StringValue) and(b Value) Value { panic(todo("")) } +func (v StringValue) cpl() Value { panic(todo("")) } +func (v StringValue) div(b Value) Value { panic(todo("")) } +func (v StringValue) eq(b Value) Value { return boolValue(v == b.(StringValue)) } +func (v StringValue) IsConst() bool { return true } +func (v StringValue) IsNonZero() bool { return true } +func (v StringValue) IsZero() bool { return false } +func (v StringValue) lsh(b Value) Value { panic(todo("")) } +func (v StringValue) mod(b Value) Value { panic(todo("")) } +func (v StringValue) mul(b Value) Value { panic(todo("")) } +func (v StringValue) neg() Value { panic(todo("")) } +func (v StringValue) neq(b Value) Value { return boolValue(v != b.(StringValue)) } +func (v StringValue) or(b Value) Value { panic(todo("")) } +func (v StringValue) rsh(b Value) Value { panic(todo("")) } +func (v StringValue) sub(b Value) Value { panic(todo("")) } +func (v StringValue) xor(b Value) Value { panic(todo("")) } + +func (v StringValue) le(b Value) Value { + return boolValue(StringID(v).String() <= StringID(b.(StringValue)).String()) +} + +func (v StringValue) ge(b Value) Value { + return boolValue(StringID(v).String() >= StringID(b.(StringValue)).String()) +} + +func (v StringValue) gt(b Value) Value { + return boolValue(StringID(v).String() > StringID(b.(StringValue)).String()) +} + +func (v StringValue) lt(b Value) Value { + return boolValue(StringID(v).String() < StringID(b.(StringValue)).String()) +} + +type Int64Value int64 + +func (v Int64Value) add(b Value) Value { return v + b.(Int64Value) } +func (v Int64Value) and(b Value) Value { return v & b.(Int64Value) } +func (v Int64Value) cpl() Value { return ^v } +func (v Int64Value) eq(b Value) Value { return boolValue(v == b.(Int64Value)) } +func (v Int64Value) ge(b Value) Value { return boolValue(v >= b.(Int64Value)) } +func (v Int64Value) gt(b Value) Value { return boolValue(v > b.(Int64Value)) } +func (v Int64Value) IsConst() bool { return true } +func (v Int64Value) IsNonZero() bool { return v != 0 } +func (v Int64Value) IsZero() bool { return v == 0 } +func (v Int64Value) le(b Value) Value { return boolValue(v <= b.(Int64Value)) } +func (v Int64Value) lt(b Value) Value { return boolValue(v < b.(Int64Value)) } +func (v Int64Value) mul(b Value) Value { return v * b.(Int64Value) } +func (v Int64Value) neg() Value { return -v } +func (v Int64Value) neq(b Value) Value { return boolValue(v != b.(Int64Value)) } +func (v Int64Value) or(b Value) Value { return v | b.(Int64Value) } +func (v Int64Value) sub(b Value) Value { return v - b.(Int64Value) } +func (v Int64Value) xor(b Value) Value { return v ^ b.(Int64Value) } + +func (v Int64Value) div(b Value) Value { + if b.IsZero() { + return nil + } + + return v / b.(Int64Value) +} + +func (v Int64Value) lsh(b Value) Value { + switch y := b.(type) { + case Int64Value: + return v << uint64(y) + case Uint64Value: + return v << y + default: + panic(todo("")) + } +} + +func (v Int64Value) rsh(b Value) Value { + switch y := b.(type) { + case Int64Value: + return v >> uint64(y) + case Uint64Value: + return v >> y + default: + panic(todo("")) + } +} + +func (v Int64Value) mod(b Value) Value { + if b.IsZero() { + return nil + } + + return v % b.(Int64Value) +} + +type Uint64Value uint64 + +func (v Uint64Value) add(b Value) Value { return v + b.(Uint64Value) } +func (v Uint64Value) and(b Value) Value { return v & b.(Uint64Value) } +func (v Uint64Value) cpl() Value { return ^v } +func (v Uint64Value) eq(b Value) Value { return boolValue(v == b.(Uint64Value)) } +func (v Uint64Value) ge(b Value) Value { return boolValue(v >= b.(Uint64Value)) } +func (v Uint64Value) gt(b Value) Value { return boolValue(v > b.(Uint64Value)) } +func (v Uint64Value) IsConst() bool { return true } +func (v Uint64Value) IsNonZero() bool { return v != 0 } +func (v Uint64Value) IsZero() bool { return v == 0 } +func (v Uint64Value) le(b Value) Value { return boolValue(v <= b.(Uint64Value)) } +func (v Uint64Value) lt(b Value) Value { return boolValue(v < b.(Uint64Value)) } +func (v Uint64Value) mul(b Value) Value { return v * b.(Uint64Value) } +func (v Uint64Value) neg() Value { return -v } +func (v Uint64Value) neq(b Value) Value { return boolValue(v != b.(Uint64Value)) } +func (v Uint64Value) or(b Value) Value { return v | b.(Uint64Value) } +func (v Uint64Value) sub(b Value) Value { return v - b.(Uint64Value) } +func (v Uint64Value) xor(b Value) Value { return v ^ b.(Uint64Value) } + +func (v Uint64Value) div(b Value) Value { + if b.IsZero() { + return nil + } + + return v / b.(Uint64Value) +} + +func (v Uint64Value) lsh(b Value) Value { + switch y := b.(type) { + case Int64Value: + return v << uint64(y) + case Uint64Value: + return v << y + default: + panic(todo("")) + } +} + +func (v Uint64Value) rsh(b Value) Value { + switch y := b.(type) { + case Int64Value: + return v >> uint64(y) + case Uint64Value: + return v >> y + default: + panic(todo("")) + } +} + +func (v Uint64Value) mod(b Value) Value { + if b.IsZero() { + return nil + } + + return v % b.(Uint64Value) +} + +type Float32Value float32 + +func (v Float32Value) add(b Value) Value { return v + b.(Float32Value) } +func (v Float32Value) and(b Value) Value { panic(todo("")) } +func (v Float32Value) cpl() Value { panic(todo("")) } +func (v Float32Value) div(b Value) Value { return v / b.(Float32Value) } +func (v Float32Value) eq(b Value) Value { return boolValue(v == b.(Float32Value)) } +func (v Float32Value) ge(b Value) Value { return boolValue(v >= b.(Float32Value)) } +func (v Float32Value) gt(b Value) Value { return boolValue(v > b.(Float32Value)) } +func (v Float32Value) IsConst() bool { return true } +func (v Float32Value) IsNonZero() bool { return v != 0 } +func (v Float32Value) IsZero() bool { return !math.Signbit(float64(v)) && v == 0 } +func (v Float32Value) le(b Value) Value { return boolValue(v <= b.(Float32Value)) } +func (v Float32Value) lsh(b Value) Value { panic(todo("")) } +func (v Float32Value) lt(b Value) Value { return boolValue(v < b.(Float32Value)) } +func (v Float32Value) mod(b Value) Value { panic(todo("")) } +func (v Float32Value) mul(b Value) Value { return v * b.(Float32Value) } +func (v Float32Value) neg() Value { return -v } +func (v Float32Value) neq(b Value) Value { return boolValue(v != b.(Float32Value)) } +func (v Float32Value) or(b Value) Value { panic(todo("")) } +func (v Float32Value) rsh(b Value) Value { panic(todo("")) } +func (v Float32Value) sub(b Value) Value { return v - b.(Float32Value) } +func (v Float32Value) xor(b Value) Value { panic(todo("")) } + +type Float64Value float64 + +func (v Float64Value) add(b Value) Value { return v + b.(Float64Value) } +func (v Float64Value) and(b Value) Value { panic(todo("")) } +func (v Float64Value) cpl() Value { panic(todo("")) } +func (v Float64Value) div(b Value) Value { return v / b.(Float64Value) } +func (v Float64Value) eq(b Value) Value { return boolValue(v == b.(Float64Value)) } +func (v Float64Value) ge(b Value) Value { return boolValue(v >= b.(Float64Value)) } +func (v Float64Value) gt(b Value) Value { return boolValue(v > b.(Float64Value)) } +func (v Float64Value) IsConst() bool { return true } +func (v Float64Value) IsNonZero() bool { return v != 0 } +func (v Float64Value) IsZero() bool { return !math.Signbit(float64(v)) && v == 0 } +func (v Float64Value) le(b Value) Value { return boolValue(v <= b.(Float64Value)) } +func (v Float64Value) lsh(b Value) Value { panic(todo("")) } +func (v Float64Value) lt(b Value) Value { return boolValue(v < b.(Float64Value)) } +func (v Float64Value) mod(b Value) Value { panic(todo("")) } +func (v Float64Value) mul(b Value) Value { return v * b.(Float64Value) } +func (v Float64Value) neg() Value { return -v } +func (v Float64Value) neq(b Value) Value { return boolValue(v != b.(Float64Value)) } +func (v Float64Value) or(b Value) Value { panic(todo("")) } +func (v Float64Value) rsh(b Value) Value { panic(todo("")) } +func (v Float64Value) sub(b Value) Value { return v - b.(Float64Value) } +func (v Float64Value) xor(b Value) Value { panic(todo("")) } + +var float128Zero = &Float128Value{N: big.NewFloat(0)} + +type Float128Value struct { + N *big.Float + NaN bool +} + +func (v *Float128Value) add(b Value) Value { return v.safe(b, func(x, y *big.Float) { x.Add(x, y) }) } +func (v *Float128Value) and(b Value) Value { panic(todo("")) } +func (v *Float128Value) cpl() Value { panic(todo("")) } +func (v *Float128Value) div(b Value) Value { return v.safe(b, func(x, y *big.Float) { x.Quo(x, y) }) } +func (v *Float128Value) eq(b Value) Value { panic(todo("")) } +func (v *Float128Value) ge(b Value) Value { panic(todo("")) } +func (v *Float128Value) gt(b Value) Value { return boolValue(v.cmp(b, -1, 0)) } +func (v *Float128Value) IsNonZero() bool { panic(todo("")) } +func (v *Float128Value) IsConst() bool { return true } +func (v *Float128Value) IsZero() bool { return !v.NaN && !v.N.Signbit() && v.cmp(float128Zero, 0) } +func (v *Float128Value) le(b Value) Value { panic(todo("")) } +func (v *Float128Value) lsh(b Value) Value { panic(todo("")) } +func (v *Float128Value) lt(b Value) Value { panic(todo("")) } +func (v *Float128Value) mod(b Value) Value { panic(todo("")) } +func (v *Float128Value) mul(b Value) Value { return v.safe(b, func(x, y *big.Float) { x.Mul(x, y) }) } +func (v *Float128Value) neg() Value { return v.safe(nil, func(x, y *big.Float) { x.Neg(x) }) } +func (v *Float128Value) neq(b Value) Value { panic(todo("")) } +func (v *Float128Value) or(b Value) Value { panic(todo("")) } +func (v *Float128Value) rsh(b Value) Value { panic(todo("")) } +func (v *Float128Value) sub(b Value) Value { return v.safe(b, func(x, y *big.Float) { x.Sub(x, y) }) } +func (v *Float128Value) xor(b Value) Value { panic(todo("")) } + +func (v *Float128Value) cmp(b Value, accept ...int) bool { + w := b.(*Float128Value) + if v.NaN || w.NaN { + return false + } + + x := v.N.Cmp(w.N) + for _, v := range accept { + if v == x { + return true + } + } + return false +} + +func (v *Float128Value) String() string { + switch { + case v == nil: + return "<nil>" + case v.NaN: + return "NaN" + default: + return fmt.Sprint(v.N) + } +} + +func (v *Float128Value) safe(b Value, f func(*big.Float, *big.Float)) (ret Value) { + var w *Float128Value + if b != nil { + w = b.(*Float128Value) + } + if v.NaN || w != nil && w.NaN { + return &Float128Value{NaN: true} + } + + r := &Float128Value{} + + defer func() { + switch x := recover().(type) { + case big.ErrNaN: + r.N = nil + r.NaN = true + ret = r + case nil: + // ok + default: + panic(x) + } + }() + + r.N = big.NewFloat(0).SetPrec(0).Set(v.N) + var wn *big.Float + if w != nil { + wn = w.N + } + f(r.N, wn) + return r +} + +type Complex64Value complex64 + +func (v Complex64Value) add(b Value) Value { return v + b.(Complex64Value) } +func (v Complex64Value) and(b Value) Value { panic(todo("")) } +func (v Complex64Value) cpl() Value { panic(todo("")) } +func (v Complex64Value) div(b Value) Value { return v / b.(Complex64Value) } +func (v Complex64Value) eq(b Value) Value { return boolValue(v == b.(Complex64Value)) } +func (v Complex64Value) ge(b Value) Value { panic(todo("")) } +func (v Complex64Value) gt(b Value) Value { panic(todo("")) } +func (v Complex64Value) IsConst() bool { return true } +func (v Complex64Value) IsNonZero() bool { return v != 0 } +func (v Complex64Value) IsZero() bool { return v == 0 } +func (v Complex64Value) le(b Value) Value { panic(todo("")) } +func (v Complex64Value) lsh(b Value) Value { panic(todo("")) } +func (v Complex64Value) lt(b Value) Value { panic(todo("")) } +func (v Complex64Value) mod(b Value) Value { panic(todo("")) } +func (v Complex64Value) mul(b Value) Value { return v * b.(Complex64Value) } +func (v Complex64Value) neg() Value { return -v } +func (v Complex64Value) neq(b Value) Value { return boolValue(v != b.(Complex64Value)) } +func (v Complex64Value) or(b Value) Value { panic(todo("")) } +func (v Complex64Value) rsh(b Value) Value { panic(todo("")) } +func (v Complex64Value) sub(b Value) Value { return v - b.(Complex64Value) } +func (v Complex64Value) xor(b Value) Value { panic(todo("")) } + +type Complex128Value complex128 + +func (v Complex128Value) add(b Value) Value { return v + b.(Complex128Value) } +func (v Complex128Value) and(b Value) Value { panic(todo("")) } +func (v Complex128Value) cpl() Value { panic(todo("")) } +func (v Complex128Value) div(b Value) Value { return v / b.(Complex128Value) } +func (v Complex128Value) eq(b Value) Value { return boolValue(v == b.(Complex128Value)) } +func (v Complex128Value) ge(b Value) Value { panic(todo("")) } +func (v Complex128Value) gt(b Value) Value { panic(todo("")) } +func (v Complex128Value) IsConst() bool { return true } +func (v Complex128Value) IsNonZero() bool { return v != 0 } +func (v Complex128Value) IsZero() bool { return v == 0 } +func (v Complex128Value) le(b Value) Value { panic(todo("")) } +func (v Complex128Value) lsh(b Value) Value { panic(todo("")) } +func (v Complex128Value) lt(b Value) Value { panic(todo("")) } +func (v Complex128Value) mod(b Value) Value { panic(todo("")) } +func (v Complex128Value) mul(b Value) Value { return v * b.(Complex128Value) } +func (v Complex128Value) neg() Value { return -v } +func (v Complex128Value) neq(b Value) Value { return boolValue(v != b.(Complex128Value)) } +func (v Complex128Value) or(b Value) Value { panic(todo("")) } +func (v Complex128Value) rsh(b Value) Value { panic(todo("")) } +func (v Complex128Value) sub(b Value) Value { return v - b.(Complex128Value) } +func (v Complex128Value) xor(b Value) Value { panic(todo("")) } + +type Complex256Value struct { + Re, Im *Float128Value +} + +func (v Complex256Value) add(b Value) Value { + w := b.(Complex256Value) + return Complex256Value{v.Re.add(w.Re).(*Float128Value), v.Im.add(w.Im).(*Float128Value)} +} + +func (v Complex256Value) and(b Value) Value { panic(todo("")) } +func (v Complex256Value) cpl() Value { panic(todo("")) } +func (v Complex256Value) div(b Value) Value { panic(todo("")) } +func (v Complex256Value) eq(b Value) Value { panic(todo("")) } +func (v Complex256Value) ge(b Value) Value { panic(todo("")) } +func (v Complex256Value) gt(b Value) Value { panic(todo("")) } +func (v Complex256Value) IsConst() bool { return true } +func (v Complex256Value) IsNonZero() bool { panic(todo("")) } +func (v Complex256Value) IsZero() bool { return v.Re.IsZero() && v.Im.IsZero() } +func (v Complex256Value) le(b Value) Value { panic(todo("")) } +func (v Complex256Value) lsh(b Value) Value { panic(todo("")) } +func (v Complex256Value) lt(b Value) Value { panic(todo("")) } +func (v Complex256Value) mod(b Value) Value { panic(todo("")) } +func (v Complex256Value) mul(b Value) Value { panic(todo("")) } +func (v Complex256Value) neg() Value { panic(todo("")) } +func (v Complex256Value) neq(b Value) Value { panic(todo("")) } +func (v Complex256Value) or(b Value) Value { panic(todo("")) } +func (v Complex256Value) rsh(b Value) Value { panic(todo("")) } +func (v Complex256Value) sub(b Value) Value { panic(todo("")) } +func (v Complex256Value) xor(b Value) Value { panic(todo("")) } + +type lvalue struct { + Operand + declarator *Declarator +} + +func (o *lvalue) ConvertTo(to Type) (r Operand) { return o.convertTo(nil, nil, to) } +func (o *lvalue) Declarator() *Declarator { return o.declarator } +func (o *lvalue) IsLValue() bool { return true } + +func (o *lvalue) IsConst() bool { + if v := o.Value(); v != nil { + return v.IsConst() + } + + d := o.Declarator() + return d != nil && (d.Linkage != None || d.IsStatic()) +} + +func (o *lvalue) convertTo(ctx *context, n Node, to Type) (r Operand) { + return &lvalue{Operand: o.Operand.convertTo(ctx, n, to), declarator: o.declarator} +} + +type funcDesignator struct { + Operand + declarator *Declarator +} + +func (o *funcDesignator) ConvertTo(to Type) (r Operand) { return o.convertTo(nil, nil, to) } +func (o *funcDesignator) Declarator() *Declarator { return o.declarator } +func (o *funcDesignator) IsLValue() bool { return false } +func (o *funcDesignator) IsConst() bool { return true } + +func (o *funcDesignator) convertTo(ctx *context, n Node, to Type) (r Operand) { + return &lvalue{Operand: o.Operand.convertTo(ctx, n, to), declarator: o.declarator} +} + +type operand struct { + abi *ABI + typ Type + value Value + offset uintptr +} + +func (o *operand) ConvertTo(to Type) (r Operand) { return o.convertTo(nil, nil, to) } +func (o *operand) Declarator() *Declarator { return nil } +func (o *operand) Offset() uintptr { return o.offset } +func (o *operand) IsLValue() bool { return false } +func (o *operand) IsNonZero() bool { return o.value != nil && o.value.IsNonZero() } +func (o *operand) IsZero() bool { return o.value != nil && o.value.IsZero() } +func (o *operand) Type() Type { return o.typ } +func (o *operand) Value() Value { return o.value } +func (o *operand) getABI() *ABI { return o.abi } + +// IsAssingmentCompatible implements Operand. +func (o *operand) IsAssingmentCompatible(lhs Type) bool { return lhs.isAssingmentCompatibleOperand(o) } + +func (o *operand) IsConst() bool { + if v := o.Value(); v != nil { + return v.IsConst() + } + + d := o.Declarator() + return d != nil && (d.Linkage != None || d.IsStatic()) +} + +// [0]6.3.1.8 +// +// Many operators that expect operands of arithmetic type cause conversions and +// yield result types in a similar way. The purpose is to determine a common +// real type for the operands and result. For the specified operands, each +// operand is converted, without change of type domain, to a type whose +// corresponding real type is the common real type. Unless explicitly stated +// otherwise, the common real type is also the corresponding real type of the +// result, whose type domain is the type domain of the operands if they are the +// same, and complex otherwise. This pattern is called the usual arithmetic +// conversions: +func usualArithmeticConversions(ctx *context, n Node, a, b Operand, normalize bool) (Operand, Operand) { + if a.Type().Kind() == Invalid || b.Type().Kind() == Invalid { + return noOperand, noOperand + } + + abi := a.getABI() + if !a.Type().IsArithmeticType() { + if ctx != nil { + ctx.errNode(n, "not an arithmetic type: %s", a.Type()) + } + return noOperand, noOperand + } + + if !b.Type().IsArithmeticType() { + if ctx != nil { + ctx.errNode(n, "not an arithmetic type: %s", b.Type()) + } + return noOperand, noOperand + } + + if a.Type() == nil || b.Type() == nil { + return a, b + } + + if normalize { + a = a.normalize(ctx, n) + b = b.normalize(ctx, n) + } + if a == noOperand || b == noOperand { + return noOperand, noOperand + } + + at := a.Type() + bt := b.Type() + cplx := at.IsComplexType() || bt.IsComplexType() + + // First, if the corresponding real type of either operand is long + // double, the other operand is converted, without change of type + // domain, to a type whose corresponding real type is long double. + if at.Kind() == ComplexLongDouble || bt.Kind() == ComplexLongDouble || at.Kind() == LongDouble || bt.Kind() == LongDouble { + switch { + case cplx: + return a.convertTo(ctx, n, abi.Type(ComplexLongDouble)), b.convertTo(ctx, n, abi.Type(ComplexLongDouble)) + default: + return a.convertTo(ctx, n, abi.Type(LongDouble)), b.convertTo(ctx, n, abi.Type(LongDouble)) + } + } + + // Otherwise, if the corresponding real type of either operand is + // double, the other operand is converted, without change of type + // domain, to a type whose corresponding real type is double. + if at.Kind() == ComplexDouble || bt.Kind() == ComplexDouble || at.Kind() == Double || bt.Kind() == Double { + switch { + case cplx: + return a.convertTo(ctx, n, abi.Type(ComplexDouble)), b.convertTo(ctx, n, abi.Type(ComplexDouble)) + default: + return a.convertTo(ctx, n, abi.Type(Double)), b.convertTo(ctx, n, abi.Type(Double)) + } + } + + // Otherwise, if the corresponding real type of either operand is + // float, the other operand is converted, without change of type + // domain, to a type whose corresponding real type is float. + if at.Kind() == ComplexFloat || bt.Kind() == ComplexFloat || at.Kind() == Float || bt.Kind() == Float { + switch { + case cplx: + return a.convertTo(ctx, n, abi.Type(ComplexFloat)), b.convertTo(ctx, n, abi.Type(ComplexFloat)) + default: + return a.convertTo(ctx, n, abi.Type(Float)), b.convertTo(ctx, n, abi.Type(Float)) + } + } + + if cplx { + panic(internalErrorf("TODO %v, %v", at, bt)) + } + + if !a.Type().IsIntegerType() || !b.Type().IsIntegerType() { + panic(todo("")) + } + + // Otherwise, the integer promotions are performed on both operands. + a = a.integerPromotion(ctx, n) + b = b.integerPromotion(ctx, n) + at = a.Type() + bt = b.Type() + + // Then the following rules are applied to the promoted operands: + + // If both operands have the same type, then no further conversion is + // needed. + if at.Kind() == bt.Kind() { + return a, b + } + + // Otherwise, if both operands have signed integer types or both have + // unsigned integer types, the operand with the type of lesser integer + // conversion rank is converted to the type of the operand with greater + // rank. + if abi.isSignedInteger(at.Kind()) == abi.isSignedInteger(bt.Kind()) { + t := a.Type() + if intConvRank[bt.Kind()] > intConvRank[at.Kind()] { + t = b.Type() + } + return a.convertTo(ctx, n, t), b.convertTo(ctx, n, t) + + } + + // Otherwise, if the operand that has unsigned integer type has rank + // greater or equal to the rank of the type of the other operand, then + // the operand with signed integer type is converted to the type of the + // operand with unsigned integer type. + switch { + case a.Type().IsSignedType(): // b is unsigned + if intConvRank[bt.Kind()] >= intConvRank[a.Type().Kind()] { + return a.convertTo(ctx, n, b.Type()), b + } + case b.Type().IsSignedType(): // a is unsigned + if intConvRank[at.Kind()] >= intConvRank[b.Type().Kind()] { + return a, b.convertTo(ctx, n, a.Type()) + } + default: + panic(fmt.Errorf("TODO %v %v", a.Type(), b.Type())) + } + + // Otherwise, if the type of the operand with signed integer type can + // represent all of the values of the type of the operand with unsigned + // integer type, then the operand with unsigned integer type is + // converted to the type of the operand with signed integer type. + var signed Type + switch { + case abi.isSignedInteger(at.Kind()): // b is unsigned + signed = a.Type() + if at.Size() > bt.Size() { + return a, b.convertTo(ctx, n, a.Type()) + } + case abi.isSignedInteger(bt.Kind()): // a is unsigned + signed = b.Type() + if bt.Size() > at.Size() { + return a.convertTo(ctx, n, b.Type()), b + } + + } + + // Otherwise, both operands are converted to the unsigned integer type + // corresponding to the type of the operand with signed integer type. + var typ Type + switch signed.Kind() { + case Int: + //TODO if a.IsEnumConst || b.IsEnumConst { + //TODO return a, b + //TODO } + + typ = abi.Type(UInt) + case Long: + typ = abi.Type(ULong) + case LongLong: + typ = abi.Type(ULongLong) + default: + panic(todo("")) + } + return a.convertTo(ctx, n, typ), b.convertTo(ctx, n, typ) +} + +// [0]6.3.1.1-2 +// +// If an int can represent all values of the original type, the value is +// converted to an int; otherwise, it is converted to an unsigned int. These +// are called the integer promotions. All other types are unchanged by the +// integer promotions. +func (o *operand) integerPromotion(ctx *context, n Node) Operand { + t := o.Type() + if t2 := integerPromotion(o.abi, t); t2.Kind() != t.Kind() { + return o.convertTo(ctx, n, t2) + } + + return o +} + +// [0]6.3.1.1-2 +// +// If an int can represent all values of the original type, the value is +// converted to an int; otherwise, it is converted to an unsigned int. These +// are called the integer promotions. All other types are unchanged by the +// integer promotions. +func integerPromotion(abi *ABI, t Type) Type { + // github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute/bf-sign-2.c + // + // This test checks promotion of bitfields. Bitfields + // should be promoted very much like chars and shorts: + // + // Bitfields (signed or unsigned) should be promoted to + // signed int if their value will fit in a signed int, + // otherwise to an unsigned int if their value will fit + // in an unsigned int, otherwise we don't promote them + // (ANSI/ISO does not specify the behavior of bitfields + // larger than an unsigned int). + if t.IsBitFieldType() { + f := t.BitField() + intBits := int(abi.Types[Int].Size) * 8 + switch { + case t.IsSignedType(): + if f.BitFieldWidth() < intBits-1 { + return abi.Type(Int) + } + default: + if f.BitFieldWidth() < intBits { + return abi.Type(Int) + } + } + return t + } + + switch t.Kind() { + case Invalid: + return t + case Char, SChar, UChar, Short, UShort: + return abi.Type(Int) + default: + return t + } +} + +func (o *operand) convertTo(ctx *context, n Node, to Type) Operand { + if o.Type().Kind() == Invalid { + return o + } + + v := o.Value() + r := &operand{abi: o.abi, typ: to, offset: o.offset, value: v} + switch v.(type) { + case nil, *InitializerValue: + return r + } + + if o.Type().Kind() == to.Kind() { + return r.normalize(ctx, n) + } + + if o.Type().IsIntegerType() { + return o.convertFromInt(ctx, n, to) + } + + if to.IsIntegerType() { + return o.convertToInt(ctx, n, to) + } + + switch o.Type().Kind() { + case Array: + switch to.Kind() { + case Ptr: + return r + default: + panic(todo("", n.Position())) + } + case ComplexFloat: + v := v.(Complex64Value) + switch to.Kind() { + case ComplexDouble: + r.value = Complex128Value(v) + case Float: + r.value = Float32Value(real(v)) + case Double: + r.value = Float64Value(real(v)) + case ComplexLongDouble: + panic(todo("", n.Position())) + default: + panic(todo("", n.Position())) + } + case ComplexDouble: + v := v.(Complex128Value) + switch to.Kind() { + case ComplexFloat: + r.value = Complex64Value(v) + case ComplexLongDouble: + //TODO panic(todo("", n.Position())) + r.value = nil + case Float: + r.value = Float32Value(real(v)) + case Double: + r.value = Float64Value(real(v)) + default: + //TODO panic(todo("", n.Position(), o.Type(), to)) + r.value = nil + } + case Float: + v := v.(Float32Value) + switch to.Kind() { + case ComplexFloat: + r.value = Complex64Value(complex(v, 0)) + case ComplexDouble: + r.value = Complex128Value(complex(v, 0)) + case Double: + r.value = Float64Value(v) + case ComplexLongDouble: + panic(todo("", n.Position())) + case LongDouble: + r.value = &Float128Value{N: big.NewFloat(float64(v))} + case Decimal32, Decimal64, Decimal128: + // ok + default: + panic(todo("695 %s", to.Kind())) + } + case Double: + v := v.(Float64Value) + switch to.Kind() { + case ComplexFloat: + r.value = Complex64Value(complex(v, 0)) + case ComplexDouble: + r.value = Complex128Value(complex(v, 0)) + case LongDouble: + f := float64(v) + switch { + case math.IsNaN(f): + r.value = &Float128Value{NaN: true} + default: + r.value = &Float128Value{N: big.NewFloat(f)} + } + case Float: + r.value = Float32Value(v) + case ComplexLongDouble: + panic(todo("", n.Position())) + case Vector: + r.value = nil + case Decimal32, Decimal64, Decimal128: + // ok + default: + panic(todo("", to.Kind())) + } + case LongDouble: + v := v.(*Float128Value) + switch to.Kind() { + case Double: + if v.NaN { + r.value = Float64Value(math.NaN()) + break + } + + d, _ := v.N.Float64() + r.value = Float64Value(d) + case Float: + if v.NaN { + r.value = Float32Value(math.NaN()) + break + } + + d, _ := v.N.Float64() + r.value = Float32Value(d) + case ComplexLongDouble: + if v.NaN { + r.value = Complex256Value{v, &Float128Value{NaN: true}} + break + } + + r.value = Complex256Value{v, &Float128Value{N: big.NewFloat(0)}} + case Decimal32, Decimal64, Decimal128: + // ok + default: + panic(todo("813 %v", to.Kind())) + } + case Ptr: + switch to.Kind() { + case Void: + return noOperand + default: + panic(internalErrorf("%v: %v y-> %v %v", n.Position(), o.Type(), to, to.Kind())) + } + default: + panic(internalErrorf("%v: %v -> %v %v", n.Position(), o.Type(), to, to.Kind())) + } + return r.normalize(ctx, n) +} + +type signedSaturationLimit struct { + fmin, fmax float64 + min, max int64 +} + +type unsignedSaturationLimit struct { + fmax float64 + max uint64 +} + +var ( + signedSaturationLimits = [...]signedSaturationLimit{ + 1: {math.Nextafter(math.MinInt32, 0), math.Nextafter(math.MaxInt32, 0), math.MinInt32, math.MaxInt32}, + 2: {math.Nextafter(math.MinInt32, 0), math.Nextafter(math.MaxInt32, 0), math.MinInt32, math.MaxInt32}, + 4: {math.Nextafter(math.MinInt32, 0), math.Nextafter(math.MaxInt32, 0), math.MinInt32, math.MaxInt32}, + 8: {math.Nextafter(math.MinInt64, 0), math.Nextafter(math.MaxInt64, 0), math.MinInt64, math.MaxInt64}, + } + + unsignedSaturationLimits = [...]unsignedSaturationLimit{ + 1: {math.Nextafter(math.MaxUint32, 0), math.MaxUint32}, + 2: {math.Nextafter(math.MaxUint32, 0), math.MaxUint32}, + 4: {math.Nextafter(math.MaxUint32, 0), math.MaxUint32}, + 8: {math.Nextafter(math.MaxUint64, 0), math.MaxUint64}, + } +) + +func (o *operand) convertToInt(ctx *context, n Node, to Type) (r Operand) { + v := o.Value() + switch o.Type().Kind() { + case Float: + v := float64(v.(Float32Value)) + switch { + case to.IsSignedType(): + limits := &signedSaturationLimits[to.Size()] + if v > limits.fmax { + return (&operand{abi: o.abi, typ: to, value: Int64Value(limits.max)}).normalize(ctx, n) + } + + if v < limits.fmin { + return (&operand{abi: o.abi, typ: to, value: Int64Value(limits.min)}).normalize(ctx, n) + } + + return (&operand{abi: o.abi, typ: to, value: Int64Value(v)}).normalize(ctx, n) + default: + limits := &unsignedSaturationLimits[to.Size()] + if v > limits.fmax { + return (&operand{abi: o.abi, typ: to, value: Uint64Value(limits.max)}).normalize(ctx, n) + } + + return (&operand{abi: o.abi, typ: to, value: Uint64Value(v)}).normalize(ctx, n) + } + case Double: + v := float64(v.(Float64Value)) + switch { + case to.IsSignedType(): + limits := &signedSaturationLimits[to.Size()] + if v > limits.fmax { + return (&operand{abi: o.abi, typ: to, value: Int64Value(limits.max)}).normalize(ctx, n) + } + + if v < limits.fmin { + return (&operand{abi: o.abi, typ: to, value: Int64Value(limits.min)}).normalize(ctx, n) + } + + return (&operand{abi: o.abi, typ: to, value: Int64Value(v)}).normalize(ctx, n) + default: + limits := &unsignedSaturationLimits[to.Size()] + if v > limits.fmax { + return (&operand{abi: o.abi, typ: to, value: Uint64Value(limits.max)}).normalize(ctx, n) + } + + return (&operand{abi: o.abi, typ: to, value: Uint64Value(v)}).normalize(ctx, n) + } + case LongDouble: + panic(todo("", n.Position())) + case Ptr: + var v uint64 + switch x := o.Value().(type) { + case Int64Value: + v = uint64(x) + case Uint64Value: + v = uint64(x) + case *InitializerValue: + return (&operand{abi: o.abi, typ: to}) + default: + panic(internalErrorf("%v: %T", n.Position(), x)) + } + switch { + case to.IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: Int64Value(v)}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: Uint64Value(v)}).normalize(ctx, n) + } + case Array: + return &operand{abi: o.abi, typ: to} + case Vector: + if o.Type().Size() == to.Size() { + return &operand{abi: o.abi, typ: to} + } + } + if ctx != nil { + ctx.errNode(n, "cannot convert %s to %s", o.Type(), to) + } + return &operand{abi: o.abi, typ: to} +} + +func (o *operand) convertFromInt(ctx *context, n Node, to Type) (r Operand) { + var v uint64 + switch x := o.Value().(type) { + case Int64Value: + v = uint64(x) + case Uint64Value: + v = uint64(x) + default: + if ctx != nil { + ctx.errNode(n, "conversion to integer: invalid value") + } + return &operand{abi: o.abi, typ: to} + } + + if to.IsIntegerType() { + switch { + case to.IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: Int64Value(v)}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: Uint64Value(v)}).normalize(ctx, n) + } + } + + switch to.Kind() { + case ComplexFloat: + switch { + case o.Type().IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: Complex64Value(complex(float64(int64(v)), 0))}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: Complex64Value(complex(float64(v), 0))}).normalize(ctx, n) + } + case ComplexDouble: + switch { + case o.Type().IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: Complex128Value(complex(float64(int64(v)), 0))}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: Complex128Value(complex(float64(v), 0))}).normalize(ctx, n) + } + case Float: + switch { + case o.Type().IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: Float32Value(float64(int64(v)))}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: Float32Value(float64(v))}).normalize(ctx, n) + } + case ComplexLongDouble: + panic(todo("", n.Position())) + case Double: + switch { + case o.Type().IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: Float64Value(int64(v))}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: Float64Value(v)}).normalize(ctx, n) + } + case LongDouble: + switch { + case o.Type().IsSignedType(): + return (&operand{abi: o.abi, typ: to, value: &Float128Value{N: big.NewFloat(0).SetInt64(int64(v))}}).normalize(ctx, n) + default: + return (&operand{abi: o.abi, typ: to, value: &Float128Value{N: big.NewFloat(0).SetUint64(v)}}).normalize(ctx, n) + } + case Ptr: + return (&operand{abi: o.abi, typ: to, value: Uint64Value(v)}).normalize(ctx, n) + case Struct, Union, Array, Void, Int128, UInt128: + return &operand{abi: o.abi, typ: to} + case Vector: + if o.Type().Size() == to.Size() { + return &operand{abi: o.abi, typ: to} + } + } + if ctx != nil { + ctx.errNode(n, "cannot convert %s to %s", o.Type(), to) + } + return &operand{abi: o.abi, typ: to} +} + +func (o *operand) normalize(ctx *context, n Node) (r Operand) { + if o.Type() == nil { + ctx.errNode(n, "operand has unsupported, invalid or incomplete type") + return noOperand + } + + if o.Type().IsIntegerType() { + switch { + case o.Type().IsSignedType(): + if x, ok := o.value.(Uint64Value); ok { + o.value = Int64Value(x) + } + default: + if x, ok := o.value.(Int64Value); ok { + o.value = Uint64Value(x) + } + } + switch x := o.Value().(type) { + case Int64Value: + if v := convertInt64(int64(x), o.Type(), o.abi); v != int64(x) { + o.value = Int64Value(v) + } + case Uint64Value: + v := uint64(x) + switch o.Type().Size() { + case 1: + v &= 0xff + case 2: + v &= 0xffff + case 4: + v &= 0xffffffff + } + if v != uint64(x) { + o.value = Uint64Value(v) + } + case *InitializerValue, nil: + // ok + default: + panic(internalErrorf("%T %v", x, x)) + } + return o + } + + switch o.Type().Kind() { + case ComplexFloat: + switch o.Value().(type) { + case Complex64Value, nil: + return o + default: + panic(todo("")) + } + case ComplexDouble: + switch o.Value().(type) { + case Complex128Value, nil: + return o + default: + panic(todo("")) + } + case ComplexLongDouble: + switch o.Value().(type) { + case Complex256Value, nil: + return o + default: + panic(todo("934 %v", o.Type().Kind())) + } + case Float: + switch o.Value().(type) { + case Float32Value, *InitializerValue, nil: + return o + default: + panic(todo("")) + } + case Double: + switch x := o.Value().(type) { + case Float64Value, *InitializerValue, nil: + return o + default: + panic(internalErrorf("%T %v", x, x)) + } + case LongDouble: + switch x := o.Value().(type) { + case *Float128Value, nil: + return o + default: + panic(internalErrorf("%T %v TODO980 %v", x, x, n.Position())) + } + case Ptr: + switch o.Value().(type) { + case Int64Value, Uint64Value, *InitializerValue, StringValue, WideStringValue, nil: + return o + default: + panic(todo("")) + } + case Array, Void, Function, Struct, Union, Vector, Decimal32, Decimal64, Decimal128: + return o + case ComplexChar, ComplexInt, ComplexLong, ComplexLongLong, ComplexShort, ComplexUInt, ComplexUShort: + //TOD + if ctx != nil { + ctx.errNode(n, "unsupported type: %s", o.Type()) + } + return noOperand + } + panic(internalErrorf("%v, %v", o.Type(), o.Type().Kind())) +} + +func convertInt64(n int64, t Type, abi *ABI) int64 { + k := t.Kind() + if k == Enum { + //TODO + } + signed := abi.isSignedInteger(k) + switch sz := abi.size(k); sz { + case 1: + switch { + case signed: + switch { + case int8(n) < 0: + return n | ^math.MaxUint8 + default: + return n & math.MaxUint8 + } + default: + return n & math.MaxUint8 + } + case 2: + switch { + case signed: + switch { + case int16(n) < 0: + return n | ^math.MaxUint16 + default: + return n & math.MaxUint16 + } + default: + return n & math.MaxUint16 + } + case 4: + switch { + case signed: + switch { + case int32(n) < 0: + return n | ^math.MaxUint32 + default: + return n & math.MaxUint32 + } + default: + return n & math.MaxUint32 + } + default: + return n + } +} + +func boolValue(b bool) Value { + if b { + return Int64Value(1) + } + + return Int64Value(0) +} + +type initializer interface { + List() []*Initializer + IsConst() bool +} + +type InitializerValue struct { + typ Type + initializer initializer +} + +func (v *InitializerValue) List() []*Initializer { + if v == nil || v.initializer == nil { + return nil + } + + return v.initializer.List() +} + +func (v *InitializerValue) IsConst() bool { + return v != nil && v.initializer != nil && v.initializer.IsConst() +} +func (v *InitializerValue) Type() Type { return v.typ } +func (v *InitializerValue) add(b Value) Value { return nil } +func (v *InitializerValue) and(b Value) Value { return nil } +func (v *InitializerValue) cpl() Value { return nil } +func (v *InitializerValue) div(b Value) Value { return nil } +func (v *InitializerValue) eq(b Value) Value { return nil } +func (v *InitializerValue) ge(b Value) Value { return nil } +func (v *InitializerValue) gt(b Value) Value { return nil } +func (v *InitializerValue) le(b Value) Value { return nil } +func (v *InitializerValue) lsh(b Value) Value { return nil } +func (v *InitializerValue) lt(b Value) Value { return nil } +func (v *InitializerValue) mod(b Value) Value { return nil } +func (v *InitializerValue) mul(b Value) Value { return nil } +func (v *InitializerValue) neg() Value { return nil } +func (v *InitializerValue) neq(b Value) Value { return nil } +func (v *InitializerValue) or(b Value) Value { return nil } +func (v *InitializerValue) rsh(b Value) Value { return nil } +func (v *InitializerValue) sub(b Value) Value { return nil } +func (v *InitializerValue) xor(b Value) Value { return nil } + +func (v *InitializerValue) IsNonZero() bool { + if v == nil { + return false + } + + for _, v := range v.List() { + if !v.AssignmentExpression.Operand.IsZero() { + return true + } + } + return false +} + +func (v *InitializerValue) IsZero() bool { + if v == nil { + return false + } + + for _, v := range v.List() { + if !v.AssignmentExpression.Operand.IsZero() { + return false + } + } + return true +} diff --git a/vendor/modernc.org/cc/v3/parser.go b/vendor/modernc.org/cc/v3/parser.go new file mode 100644 index 00000000..d73b2c6b --- /dev/null +++ b/vendor/modernc.org/cc/v3/parser.go @@ -0,0 +1,4292 @@ +// 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 ( + "bytes" + "fmt" + "hash/maphash" + "strings" +) + +const ( + unicodePrivateAreaFirst = 0xe000 + unicodePrivateAreaLast = 0xf8ff +) + +var ( + noDeclSpecs = &DeclarationSpecifiers{} + panicOnParserError bool //TODOOK + + idChar = dict.sid("char") + idComma = dict.sid(",") + idConst = dict.sid("const") + idEq = dict.sid("=") + idFFlush = dict.sid("fflush") + idFprintf = dict.sid("fprintf") + idFunc = dict.sid("__func__") + idLBracket = dict.sid("[") + idLParen = dict.sid("(") + idRBracket = dict.sid("]") + idRParen = dict.sid(")") + idSemicolon = dict.sid(";") + idStatic = dict.sid("static") + idStderr = dict.sid("stderr") +) + +// Values of Token.Rune for lexemes. +const ( + _ = iota + unicodePrivateAreaFirst //TODOOK + + ACCUM // _Accum + ADDASSIGN // += + ALIGNAS // _Alignas + ALIGNOF // _Alignof + ANDAND // && + ANDASSIGN // &= + ARROW // -> + ASM // __asm__ + ATOMIC // _Atomic + ATTRIBUTE // __attribute__ + AUTO // auto + BOOL // _Bool + BREAK // break + BUILTINCHOOSEEXPR // __builtin_choose_expr + BUILTINTYPESCOMPATIBLE // __builtin_types_compatible_p + CASE // case + CHAR // char + CHARCONST // 'a' + COMPLEX // _Complex + CONST // const + CONTINUE // continue + DDD // ... + DEC // -- + DECIMAL128 // _Decimal128 + DECIMAL32 // _Decimal32 + DECIMAL64 // _Decimal64 + DEFAULT // default + DIVASSIGN // /= + DO // do + DOUBLE // double + ELSE // else + ENUM // enum + ENUMCONST // foo in enum x { foo, bar }; + EQ // == + EXTERN // extern + FLOAT // float + FLOAT128 // _Float128 + FLOAT16 // __fp16 + FLOAT32 // _Float32 + FLOAT32X // _Float32x + FLOAT64 // _Float64 + FLOAT64X // _Float64x + FLOAT80 // __float80 + FLOATCONST // 1.23 + FOR // for + FRACT // _Fract + GEQ // >= + GOTO // goto + IDENTIFIER // foo + IF // if + IMAG // __imag__ + INC // ++ + INLINE // inline + INT // int + INT8 // __int8 + INT16 // __int16 + INT32 // __int32 + INT64 // __int64 + INT128 // __int128 + INTCONST // 42 + LABEL // __label__ + LEQ // <= + LONG // long + LONGCHARCONST // L'a' + LONGSTRINGLITERAL // L"foo" + LSH // << + LSHASSIGN // <<= + MODASSIGN // %= + MULASSIGN // *= + NEQ // != + NORETURN // _Noreturn + ORASSIGN // |= + OROR // || + PPNUMBER // .32e. + PPPASTE // ## + PRAGMASTDC // __pragma_stdc + REAL // __real__ + REGISTER // register + RESTRICT // restrict + RETURN // return + RSH // >> + RSHASSIGN // >>= + SAT // _Sat + SHORT // short + SIGNED // signed + SIZEOF // sizeof + STATIC // static + STRINGLITERAL // "foo" + STRUCT // struct + SUBASSIGN // -= + SWITCH // switch + THREADLOCAL // _Thread_local + TYPEDEF // typedef + TYPEDEFNAME // int_t in typedef int int_t; + TYPEOF // typeof + UNION // union + UNSIGNED // unsigned + VOID // void + VOLATILE // volatile + WHILE // while + XORASSIGN // ^= + + lastTok +) + +var ( + tokNames = map[rune]StringID{ + ACCUM: dict.sid("ACCUM"), + ADDASSIGN: dict.sid("ADDASSIGN"), + ALIGNAS: dict.sid("ALIGNAS"), + ALIGNOF: dict.sid("ALIGNOF"), + ANDAND: dict.sid("ANDAND"), + ANDASSIGN: dict.sid("ANDASSIGN"), + ARROW: dict.sid("ARROW"), + ASM: dict.sid("ASM"), + ATOMIC: dict.sid("ATOMIC"), + ATTRIBUTE: dict.sid("ATTRIBUTE"), + AUTO: dict.sid("AUTO"), + BOOL: dict.sid("BOOL"), + BREAK: dict.sid("BREAK"), + BUILTINCHOOSEEXPR: dict.sid("BUILTINCHOOSEEXPR"), + BUILTINTYPESCOMPATIBLE: dict.sid("BUILTINTYPESCOMPATIBLE"), + CASE: dict.sid("CASE"), + CHAR: dict.sid("CHAR"), + CHARCONST: dict.sid("CHARCONST"), + COMPLEX: dict.sid("COMPLEX"), + CONST: dict.sid("CONST"), + CONTINUE: dict.sid("CONTINUE"), + DDD: dict.sid("DDD"), + DEC: dict.sid("DEC"), + DECIMAL128: dict.sid("DECIMAL128"), + DECIMAL32: dict.sid("DECIMAL32"), + DECIMAL64: dict.sid("DECIMAL64"), + DEFAULT: dict.sid("DEFAULT"), + DIVASSIGN: dict.sid("DIVASSIGN"), + DO: dict.sid("DO"), + DOUBLE: dict.sid("DOUBLE"), + ELSE: dict.sid("ELSE"), + ENUM: dict.sid("ENUM"), + ENUMCONST: dict.sid("ENUMCONST"), + EQ: dict.sid("EQ"), + EXTERN: dict.sid("EXTERN"), + FLOAT128: dict.sid("FLOAT128"), + FLOAT16: dict.sid("FLOAT16"), + FLOAT32: dict.sid("FLOAT32"), + FLOAT32X: dict.sid("FLOAT32X"), + FLOAT64: dict.sid("FLOAT64"), + FLOAT64X: dict.sid("FLOAT64X"), + FLOAT80: dict.sid("FLOAT80"), + FLOAT: dict.sid("FLOAT"), + FLOATCONST: dict.sid("FLOATCONST"), + FOR: dict.sid("FOR"), + FRACT: dict.sid("FRACT"), + GEQ: dict.sid("GEQ"), + GOTO: dict.sid("GOTO"), + IDENTIFIER: dict.sid("IDENTIFIER"), + IF: dict.sid("IF"), + IMAG: dict.sid("IMAG"), + INC: dict.sid("INC"), + INLINE: dict.sid("INLINE"), + INT8: dict.sid("INT8"), + INT16: dict.sid("INT16"), + INT32: dict.sid("INT32"), + INT64: dict.sid("INT64"), + INT128: dict.sid("INT128"), + INT: dict.sid("INT"), + INTCONST: dict.sid("INTCONST"), + LABEL: dict.sid("LABEL"), + LEQ: dict.sid("LEQ"), + LONG: dict.sid("LONG"), + LONGCHARCONST: dict.sid("LONGCHARCONST"), + LONGSTRINGLITERAL: dict.sid("LONGSTRINGLITERAL"), + LSH: dict.sid("LSH"), + LSHASSIGN: dict.sid("LSHASSIGN"), + MODASSIGN: dict.sid("MODASSIGN"), + MULASSIGN: dict.sid("MULASSIGN"), + NEQ: dict.sid("NEQ"), + NORETURN: dict.sid("NORETURN"), + ORASSIGN: dict.sid("ORASSIGN"), + OROR: dict.sid("OROR"), + PPNUMBER: dict.sid("PPNUMBER"), + PPPASTE: dict.sid("PPPASTE"), + PRAGMASTDC: dict.sid("PPPRAGMASTDC"), + REAL: dict.sid("REAL"), + REGISTER: dict.sid("REGISTER"), + RESTRICT: dict.sid("RESTRICT"), + RETURN: dict.sid("RETURN"), + RSH: dict.sid("RSH"), + RSHASSIGN: dict.sid("RSHASSIGN"), + SAT: dict.sid("SAT"), + SHORT: dict.sid("SHORT"), + SIGNED: dict.sid("SIGNED"), + SIZEOF: dict.sid("SIZEOF"), + STATIC: dict.sid("STATIC"), + STRINGLITERAL: dict.sid("STRINGLITERAL"), + STRUCT: dict.sid("STRUCT"), + SUBASSIGN: dict.sid("SUBASSIGN"), + SWITCH: dict.sid("SWITCH"), + THREADLOCAL: dict.sid("THREADLOCAL"), + TYPEDEF: dict.sid("TYPEDEF"), + TYPEDEFNAME: dict.sid("TYPEDEFNAME"), + TYPEOF: dict.sid("TYPEOF"), + UNION: dict.sid("UNION"), + UNSIGNED: dict.sid("UNSIGNED"), + VOID: dict.sid("VOID"), + VOLATILE: dict.sid("VOLATILE"), + WHILE: dict.sid("WHILE"), + XORASSIGN: dict.sid("XORASSIGN"), + } + + keywords = map[StringID]rune{ + + // [0], 6.4.1 + dict.sid("auto"): AUTO, + dict.sid("break"): BREAK, + dict.sid("case"): CASE, + dict.sid("char"): CHAR, + dict.sid("const"): CONST, + dict.sid("continue"): CONTINUE, + dict.sid("default"): DEFAULT, + dict.sid("do"): DO, + dict.sid("double"): DOUBLE, + dict.sid("else"): ELSE, + dict.sid("enum"): ENUM, + dict.sid("extern"): EXTERN, + dict.sid("float"): FLOAT, + dict.sid("for"): FOR, + dict.sid("goto"): GOTO, + dict.sid("if"): IF, + dict.sid("inline"): INLINE, + dict.sid("int"): INT, + dict.sid("long"): LONG, + dict.sid("register"): REGISTER, + dict.sid("restrict"): RESTRICT, + dict.sid("return"): RETURN, + dict.sid("short"): SHORT, + dict.sid("signed"): SIGNED, + dict.sid("sizeof"): SIZEOF, + dict.sid("static"): STATIC, + dict.sid("struct"): STRUCT, + dict.sid("switch"): SWITCH, + dict.sid("typedef"): TYPEDEF, + dict.sid("union"): UNION, + dict.sid("unsigned"): UNSIGNED, + dict.sid("void"): VOID, + dict.sid("volatile"): VOLATILE, + dict.sid("while"): WHILE, + + dict.sid("_Alignas"): ALIGNAS, + dict.sid("_Alignof"): ALIGNOF, + dict.sid("_Atomic"): ATOMIC, + dict.sid("_Bool"): BOOL, + dict.sid("_Complex"): COMPLEX, + dict.sid("_Noreturn"): NORETURN, + dict.sid("_Thread_local"): THREADLOCAL, + dict.sid("__alignof"): ALIGNOF, + dict.sid("__alignof__"): ALIGNOF, + dict.sid("__asm"): ASM, + dict.sid("__asm__"): ASM, + dict.sid("__attribute"): ATTRIBUTE, + dict.sid("__attribute__"): ATTRIBUTE, + dict.sid("__complex"): COMPLEX, + dict.sid("__complex__"): COMPLEX, + dict.sid("__const"): CONST, + dict.sid("__inline"): INLINE, + dict.sid("__inline__"): INLINE, + dict.sid("__int16"): INT16, + dict.sid("__int32"): INT32, + dict.sid("__int64"): INT64, + dict.sid("__int8"): INT8, + dict.sid("__pragma_stdc"): PRAGMASTDC, + dict.sid("__restrict"): RESTRICT, + dict.sid("__restrict__"): RESTRICT, + dict.sid("__signed"): SIGNED, + dict.sid("__signed__"): SIGNED, + dict.sid("__thread"): THREADLOCAL, + dict.sid("__typeof"): TYPEOF, + dict.sid("__typeof__"): TYPEOF, + dict.sid("__volatile"): VOLATILE, + dict.sid("__volatile__"): VOLATILE, + dict.sid("typeof"): TYPEOF, + } + + gccKeywords = map[StringID]rune{ + dict.sid("_Accum"): ACCUM, + dict.sid("_Decimal128"): DECIMAL128, + dict.sid("_Decimal32"): DECIMAL32, + dict.sid("_Decimal64"): DECIMAL64, + dict.sid("_Float128"): FLOAT128, + dict.sid("_Float16"): FLOAT16, + dict.sid("_Float32"): FLOAT32, + dict.sid("_Float32x"): FLOAT32X, + dict.sid("_Float64"): FLOAT64, + dict.sid("_Float64x"): FLOAT64X, + dict.sid("_Fract"): FRACT, + dict.sid("_Sat"): SAT, + dict.sid("__builtin_choose_expr"): BUILTINCHOOSEEXPR, + dict.sid("__builtin_types_compatible_p"): BUILTINTYPESCOMPATIBLE, + dict.sid("__float80"): FLOAT80, + dict.sid("__fp16"): FLOAT16, + dict.sid("__imag"): IMAG, + dict.sid("__imag__"): IMAG, + dict.sid("__int128"): INT128, + dict.sid("__label__"): LABEL, + dict.sid("__real"): REAL, + dict.sid("__real__"): REAL, + } +) + +func init() { + for r := rune(0xe001); r < lastTok; r++ { + if _, ok := tokNames[r]; !ok { + panic(internalError()) + } + } + for k, v := range keywords { + gccKeywords[k] = v + } +} + +func tokName(r rune) string { + switch { + case r < 0: + return "<EOF>" + case r >= unicodePrivateAreaFirst && r <= unicodePrivateAreaLast: + return tokNames[r].String() + default: + return fmt.Sprintf("%+q", r) + } +} + +type parser struct { + block *CompoundStatement + ctx *context + currFn *FunctionDefinition + declScope Scope + fileScope Scope + hash *maphash.Hash + in chan *[]Token + inBuf []Token + inBufp *[]Token + key sharedFunctionDefinitionKey + prev Token + resolveScope Scope + resolvedIn Scope // Typedef name + scopes int + sepLen int + seps []StringID + strcatLen int + strcats []StringID + switches int + + tok Token + + closed bool + errored bool + ignoreKeywords bool + typedefNameEnabled bool +} + +func newParser(ctx *context, in chan *[]Token) *parser { + s := Scope{} + var hash *maphash.Hash + if s := ctx.cfg.SharedFunctionDefinitions; s != nil { + hash = &s.hash + } + return &parser{ + ctx: ctx, + declScope: s, + fileScope: s, + hash: hash, + in: in, + resolveScope: s, + } +} + +func (p *parser) openScope(skip bool) { + p.scopes++ + p.declScope = p.declScope.new() + if skip { + p.declScope[scopeSkip] = nil + } + p.resolveScope = p.declScope + // var a []string + // for s := p.declScope; s != nil; s = s.Parent() { + // a = append(a, fmt.Sprintf("%p", s)) + // } + // trc("openScope(%v) %p: %v", skip, p.declScope, strings.Join(a, " ")) +} + +func (p *parser) closeScope() { + // declScope := p.declScope + p.declScope = p.declScope.Parent() + p.resolveScope = p.declScope + p.scopes-- + // var a []string + // for s := p.declScope; s != nil; s = s.Parent() { + // a = append(a, fmt.Sprintf("%p", s)) + // } + // trc("%p.closeScope %v", declScope, strings.Join(a, " ")) +} + +func (p *parser) err0(consume bool, msg string, args ...interface{}) { + if panicOnParserError { //TODOOK + s := fmt.Sprintf("FAIL: "+msg, args...) + panic(fmt.Sprintf("%s\n%s: ", s, PrettyString(p.tok))) //TODOOK + } + // s := fmt.Sprintf("FAIL: "+p.tok.Position().String()+": "+msg, args...) + // caller("%s: %s: ", s, PrettyString(p.tok)) + p.errored = true + if consume { + p.tok.Rune = 0 + } + if p.ctx.err(p.tok.Position(), "`%s`: "+msg, append([]interface{}{p.tok}, args...)...) { + p.closed = true + } +} + +func (p *parser) err(msg string, args ...interface{}) { p.err0(true, msg, args...) } + +func (p *parser) rune() rune { + if p.tok.Rune == 0 { + p.next() + } + return p.tok.Rune +} + +func (p *parser) shift() (r Token) { + if p.tok.Rune == 0 { + p.next() + } + r = p.tok + p.tok.Rune = 0 + // dbg("", shift(r)) + return r +} + +func (p *parser) unget(toks ...Token) { //TODO injected __func__ has two trailing semicolons, why? + p.inBuf = append(toks, p.inBuf...) + // fmt.Printf("unget %q\n", tokStr(toks, "|")) //TODO- +} + +func (p *parser) peek(handleTypedefname bool) rune { + if p.closed { + return -1 + } + + if len(p.inBuf) == 0 { + if p.inBufp != nil { + tokenPool.Put(p.inBufp) + } + var ok bool + if p.inBufp, ok = <-p.in; !ok { + // dbg("parser: EOF") + return -1 + } + + p.inBuf = *p.inBufp + // dbg("parser receives: %q", tokStr(p.inBuf, "|")) + // fmt.Printf("parser receives %v: %q\n", p.inBuf[0].Position(), tokStr(p.inBuf, "|")) //TODO- + } + tok := p.inBuf[0] + r := tok.Rune + if r == IDENTIFIER { + if x, ok := p.ctx.keywords[p.inBuf[0].Value]; ok && !p.ignoreKeywords { + return x + } + + if handleTypedefname { + nm := tok.Value + seq := tok.seq + for s := p.resolveScope; s != nil; s = s.Parent() { + for _, v := range s[nm] { + switch x := v.(type) { + case *Declarator: + if !x.isVisible(seq) { + continue + } + + if x.IsTypedefName && p.peek(false) != ':' { + return TYPEDEFNAME + } + + return IDENTIFIER + case *Enumerator: + return IDENTIFIER + case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: + // nop + default: + panic(internalErrorf("%T", x)) + } + } + } + } + } + return r +} + +func (p *parser) next() { + if p.closed { + // dbg("parser: EOF") + p.tok.Rune = -1 + return + } + +more: + if len(p.inBuf) == 0 { + if p.inBufp != nil { + tokenPool.Put(p.inBufp) + } + var ok bool + if p.inBufp, ok = <-p.in; !ok { + // dbg("parser: EOF") + p.closed = true + p.tok.Rune = -1 + return + } + + p.inBuf = *p.inBufp + // dbg("parser receives: %q", tokStr(p.inBuf, "|")) + // fmt.Printf("parser receives %v: %q\n", p.inBuf[0].Position(), tokStr(p.inBuf, "|")) //TODO- + } + p.tok = p.inBuf[0] + switch p.tok.Rune { + case STRINGLITERAL, LONGSTRINGLITERAL: + switch p.prev.Rune { + case STRINGLITERAL, LONGSTRINGLITERAL: + p.strcatLen += len(p.tok.Value.String()) + p.strcats = append(p.strcats, p.tok.Value) + p.sepLen += len(p.tok.Sep.String()) + p.seps = append(p.seps, p.tok.Sep) + p.inBuf = p.inBuf[1:] + goto more + default: + p.strcatLen = len(p.tok.Value.String()) + p.strcats = []StringID{p.tok.Value} + p.sepLen = len(p.tok.Sep.String()) + p.seps = []StringID{p.tok.Sep} + p.prev = p.tok + p.inBuf = p.inBuf[1:] + goto more + } + default: + switch p.prev.Rune { + case STRINGLITERAL, LONGSTRINGLITERAL: + p.tok = p.prev + var b bytes.Buffer + b.Grow(p.strcatLen) + for _, v := range p.strcats { + b.WriteString(v.String()) + } + p.tok.Value = dict.id(b.Bytes()) + b.Reset() + b.Grow(p.sepLen) + for _, v := range p.seps { + b.WriteString(v.String()) + } + p.tok.Sep = dict.id(b.Bytes()) + p.prev.Rune = 0 + default: + p.inBuf = p.inBuf[1:] + } + } + p.resolvedIn = nil +out: + switch p.tok.Rune { + case IDENTIFIER: + nm := p.tok.Value + if x, ok := p.ctx.keywords[nm]; ok && !p.ignoreKeywords { + p.tok.Rune = x + break + } + + if p.typedefNameEnabled { + seq := p.tok.seq + // dbg("checking for typedefname in scope %p", p.resolveScope) + for s := p.resolveScope; s != nil; s = s.Parent() { + // dbg("scope %p", s) + for _, v := range s[nm] { + // dbg("%v: %T", nm, v) + switch x := v.(type) { + case *Declarator: + if !x.isVisible(seq) { + continue + } + + // dbg("", x.isVisible(pos), x.IsTypedefName) + if x.IsTypedefName && p.peek(false) != ':' { + p.tok.Rune = TYPEDEFNAME + p.resolvedIn = s + } + + p.typedefNameEnabled = false + break out + case *Enumerator: + if x.isVisible(seq) { + break out + } + case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: + // nop + default: + panic(internalError()) + } + } + } + } + case PPNUMBER: + switch s := p.tok.Value.String(); { + case strings.ContainsAny(s, ".+-ijpIJP"): + p.tok.Rune = FLOATCONST + case strings.HasPrefix(s, "0x") || strings.HasPrefix(s, "0X"): + p.tok.Rune = INTCONST + case strings.ContainsAny(s, "Ee"): + p.tok.Rune = FLOATCONST + default: + p.tok.Rune = INTCONST + } + } + if p.ctx.cfg.SharedFunctionDefinitions != nil { + p.hashTok() + } + // dbg("parser.next p.tok %v", PrettyString(p.tok)) + // fmt.Printf("%s%s/* %s */", p.tok.Sep, p.tok.Value, tokName(p.tok.Rune)) //TODO- +} + +func (p *parser) hashTok() { + n := p.tok.Rune + for i := 0; i < 4; i++ { + p.hash.WriteByte(byte(n)) + n >>= 8 + } + n = int32(p.tok.Value) + for i := 0; i < 4; i++ { + p.hash.WriteByte(byte(n)) + n >>= 8 + } +} + +// [0], 6.5.1 Primary expressions +// +// primary-expression: +// identifier +// constant +// string-literal +// ( expression ) +// ( compound-statement ) +func (p *parser) primaryExpression() *PrimaryExpression { + var kind PrimaryExpressionCase + var resolvedIn Scope + var resolvedTo Node +out: + switch p.rune() { + case IDENTIFIER: + kind = PrimaryExpressionIdent + nm := p.tok.Value + seq := p.tok.seq + for s := p.resolveScope; s != nil; s = s.Parent() { + for _, v := range s[nm] { + switch x := v.(type) { + case *Enumerator: + if x.isVisible(seq) { + resolvedIn = s + resolvedTo = x + p.tok.Rune = ENUMCONST + kind = PrimaryExpressionEnum + break out + } + case *Declarator: + if x.IsTypedefName || !x.isVisible(seq) { + continue + } + + resolvedIn = s + resolvedTo = x + break out + case *EnumSpecifier, *StructOrUnionSpecifier, *StructDeclarator, *LabeledStatement: + // nop + default: + panic(internalError()) + } + } + } + + if !p.ctx.cfg.ignoreUndefinedIdentifiers && p.ctx.cfg.RejectLateBinding { + p.err0(false, "front-end: undefined: %s", nm) + } + case INTCONST: + kind = PrimaryExpressionInt + case FLOATCONST: + kind = PrimaryExpressionFloat + case ENUMCONST: + kind = PrimaryExpressionEnum + case CHARCONST: + kind = PrimaryExpressionChar + case LONGCHARCONST: + kind = PrimaryExpressionLChar + case STRINGLITERAL: + kind = PrimaryExpressionString + case LONGSTRINGLITERAL: + kind = PrimaryExpressionLString + case '(': + t := p.shift() + switch p.peek(false) { + case '{': + if p.ctx.cfg.RejectStatementExpressions { + p.err0(false, "statement expressions not allowed") + } + s := p.compoundStatement(nil, nil) + var t2 Token + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + return &PrimaryExpression{Case: PrimaryExpressionStmt, Token: t, CompoundStatement: s, Token2: t2, lexicalScope: p.declScope} + default: + e := p.expression() + var t2 Token + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + return &PrimaryExpression{Case: PrimaryExpressionExpr, Token: t, Expression: e, Token2: t2, lexicalScope: p.declScope} + } + default: + p.err("expected primary-expression") + return nil + } + + return &PrimaryExpression{Case: kind, Token: p.shift(), lexicalScope: p.declScope, resolvedIn: resolvedIn, resolvedTo: resolvedTo} +} + +// [0], 6.5.2 Postfix operators +// +// postfix-expression: +// primary-expression +// postfix-expression [ expression ] +// postfix-expression ( argument-expression-list_opt ) +// postfix-expression . identifier +// postfix-expression -> identifier +// postfix-expression ++ +// postfix-expression -- +// ( type-name ) { initializer-list } +// ( type-name ) { initializer-list , } +// __builtin_types_compatible_p ( type-name , type-name ) +func (p *parser) postfixExpression(typ *TypeName) (r *PostfixExpression) { + var t, t2, t3, t4, t5 Token +out: + switch { + case typ != nil: + switch p.rune() { + case '{': + t3 = p.shift() + default: + p.err("expected {") + return nil + } + + var list *InitializerList + switch p.rune() { + case '}': + if p.ctx.cfg.RejectEmptyInitializerList { + p.err0(false, "expected initializer-list") + } + default: + list = p.initializerList(nil) + if p.rune() == ',' { + t4 = p.shift() + } + } + switch p.rune() { + case '}': + t5 = p.shift() + default: + p.err("expected }") + } + r = &PostfixExpression{Case: PostfixExpressionComplit, Token: t, TypeName: typ, Token2: t2, Token3: t3, InitializerList: list, Token4: t4, Token5: t5} + break out + default: + switch p.rune() { + case BUILTINCHOOSEEXPR: + t = p.shift() + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + expr1 := p.assignmentExpression() + switch p.rune() { + case ',': + t3 = p.shift() + default: + p.err("expected ,") + } + expr2 := p.assignmentExpression() + switch p.rune() { + case ',': + t4 = p.shift() + default: + p.err("expected ,") + } + expr3 := p.assignmentExpression() + switch p.rune() { + case ')': + t5 = p.shift() + default: + p.err("expected )") + } + return &PostfixExpression{Case: PostfixExpressionChooseExpr, Token: t, Token2: t2, Token3: t3, Token4: t4, Token5: t5, AssignmentExpression: expr1, AssignmentExpression2: expr2, AssignmentExpression3: expr3} + case BUILTINTYPESCOMPATIBLE: + t = p.shift() + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + typ := p.typeName() + switch p.rune() { + case ',': + t3 = p.shift() + default: + p.err("expected ,") + } + typ2 := p.typeName() + switch p.rune() { + case ')': + t4 = p.shift() + default: + p.err("expected )") + } + return &PostfixExpression{Case: PostfixExpressionTypeCmp, Token: t, Token2: t2, TypeName: typ, Token3: t3, TypeName2: typ2, Token4: t4} + case '(': + switch p.peek(true) { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE: + p.typedefNameEnabled = true + t = p.shift() + typ := p.typeName() + p.typedefNameEnabled = false + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + switch p.rune() { + case '{': + t3 = p.shift() + default: + p.err("expected {") + } + var list *InitializerList + switch p.rune() { + case '}': + if p.ctx.cfg.RejectEmptyInitializerList { + p.err0(false, "expected initializer-list") + } + default: + list = p.initializerList(nil) + if p.rune() == ',' { + t4 = p.shift() + } + } + switch p.rune() { + case '}': + t5 = p.shift() + default: + p.err("expected }") + } + r = &PostfixExpression{Case: PostfixExpressionComplit, Token: t, TypeName: typ, Token2: t2, Token3: t3, InitializerList: list, Token4: t4, Token5: t5} + break out + } + + fallthrough + default: + pe := p.primaryExpression() + if pe == nil { + return nil + } + + r = &PostfixExpression{Case: PostfixExpressionPrimary, PrimaryExpression: pe} + } + } + + for { + switch p.rune() { + case '[': + t = p.shift() + e := p.expression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &PostfixExpression{Case: PostfixExpressionIndex, PostfixExpression: r, Token: t, Expression: e, Token2: t2} + case '(': + t = p.shift() + list := p.argumentExpressionListOpt() + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &PostfixExpression{Case: PostfixExpressionCall, PostfixExpression: r, Token: t, ArgumentExpressionList: list, Token2: t2} + case '.': + t = p.shift() + switch p.rune() { + case IDENTIFIER: + t2 = p.shift() + default: + p.err("expected identifier") + } + r = &PostfixExpression{Case: PostfixExpressionSelect, PostfixExpression: r, Token: t, Token2: t2} + case ARROW: + t = p.shift() + switch p.rune() { + case IDENTIFIER: + t2 = p.shift() + default: + p.err("expected identifier") + } + r = &PostfixExpression{Case: PostfixExpressionPSelect, PostfixExpression: r, Token: t, Token2: t2} + case INC: + r = &PostfixExpression{Case: PostfixExpressionInc, PostfixExpression: r, Token: p.shift()} + case DEC: + r = &PostfixExpression{Case: PostfixExpressionDec, PostfixExpression: r, Token: p.shift()} + default: + return r + } + } +} + +// argument-expression-list: +// assignment-expression +// argument-expression-list , assignment-expression +func (p *parser) argumentExpressionListOpt() (r *ArgumentExpressionList) { + if p.rune() == ')' { + return nil + } + + e := p.assignmentExpression() + if e == nil { + return nil + } + + r = &ArgumentExpressionList{AssignmentExpression: e} + for prev := r; ; prev = prev.ArgumentExpressionList { + switch p.rune() { + case ',': + t := p.shift() + prev.ArgumentExpressionList = &ArgumentExpressionList{Token: t, AssignmentExpression: p.assignmentExpression()} + case ')': + return r + default: + p.err("expected , or )") + return r + } + } +} + +// [0], 6.5.3 Unary operators +// +// unary-expression: +// postfix-expression +// ++ unary-expression +// -- unary-expression +// unary-operator cast-expression +// sizeof unary-expression +// sizeof ( type-name ) +// && identifier +// _Alignof unary-expression +// _Alignof ( type-name ) +// __imag__ unary-expression +// __real__ unary-expression +// +// unary-operator: one of +// & * + - ~ ! +func (p *parser) unaryExpression(typ *TypeName) *UnaryExpression { + if typ != nil { + return &UnaryExpression{Case: UnaryExpressionPostfix, PostfixExpression: p.postfixExpression(typ), lexicalScope: p.declScope} + } + + var kind UnaryExpressionCase + var t, t2, t3 Token + switch p.rune() { + case INC: + t = p.shift() + return &UnaryExpression{Case: UnaryExpressionInc, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + case DEC: + t = p.shift() + return &UnaryExpression{Case: UnaryExpressionDec, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + case '&': + kind = UnaryExpressionAddrof + case '*': + kind = UnaryExpressionDeref + case '+': + kind = UnaryExpressionPlus + case '-': + kind = UnaryExpressionMinus + case '~': + kind = UnaryExpressionCpl + case '!': + kind = UnaryExpressionNot + case SIZEOF: + t = p.shift() + switch p.rune() { + case '(': + switch p.peek(true) { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE: + p.typedefNameEnabled = true + t2 = p.shift() + typ := p.typeName() + p.typedefNameEnabled = false + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + if p.peek(false) == '{' { + return &UnaryExpression{Case: UnaryExpressionSizeofExpr, Token: t, UnaryExpression: p.unaryExpression(typ), lexicalScope: p.declScope} + } + + return &UnaryExpression{Case: UnaryExpressionSizeofType, Token: t, Token2: t2, TypeName: typ, Token3: t3, lexicalScope: p.declScope} + } + + fallthrough + default: + return &UnaryExpression{Case: UnaryExpressionSizeofExpr, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + } + case ANDAND: + t = p.shift() + var t2 Token + switch p.rune() { + case IDENTIFIER: + t2 = p.shift() + default: + p.err("expected identifier") + } + return &UnaryExpression{Case: UnaryExpressionLabelAddr, Token: t, Token2: t2, lexicalScope: p.declScope} + case ALIGNOF: + t = p.shift() + switch p.rune() { + case '(': + switch p.peek(true) { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE, + ALIGNAS: + t2 = p.shift() + typ := p.typeName() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &UnaryExpression{Case: UnaryExpressionAlignofType, Token: t, Token2: t2, TypeName: typ, Token3: t2, lexicalScope: p.declScope} + default: + return &UnaryExpression{Case: UnaryExpressionAlignofExpr, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + } + default: + return &UnaryExpression{Case: UnaryExpressionAlignofExpr, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + } + case IMAG: + t = p.shift() + return &UnaryExpression{Case: UnaryExpressionImag, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + case REAL: + t = p.shift() + return &UnaryExpression{Case: UnaryExpressionReal, Token: t, UnaryExpression: p.unaryExpression(nil), lexicalScope: p.declScope} + default: + return &UnaryExpression{Case: UnaryExpressionPostfix, PostfixExpression: p.postfixExpression(nil), lexicalScope: p.declScope} + } + + t = p.shift() + return &UnaryExpression{Case: kind, Token: t, CastExpression: p.castExpression(), lexicalScope: p.declScope} +} + +// [0], 6.5.4 Cast operators +// +// cast-expression: +// unary-expression +// ( type-name ) cast-expression +func (p *parser) castExpression() *CastExpression { + var t, t2 Token + switch p.rune() { + case '(': + switch p.peek(true) { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE: + p.typedefNameEnabled = true + t = p.shift() + typ := p.typeName() + p.typedefNameEnabled = false + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + if p.peek(false) == '{' { + return &CastExpression{Case: CastExpressionUnary, UnaryExpression: p.unaryExpression(typ)} + } + + return &CastExpression{Case: CastExpressionCast, Token: t, TypeName: typ, Token2: t2, CastExpression: p.castExpression()} + } + + fallthrough + default: + return &CastExpression{Case: CastExpressionUnary, UnaryExpression: p.unaryExpression(nil)} + } +} + +// [0], 6.5.5 Multiplicative operators +// +// multiplicative-expression: +// cast-expression +// multiplicative-expression * cast-expression +// multiplicative-expression / cast-expression +// multiplicative-expression % cast-expression +func (p *parser) multiplicativeExpression() (r *MultiplicativeExpression) { + r = &MultiplicativeExpression{Case: MultiplicativeExpressionCast, CastExpression: p.castExpression()} + for { + var kind MultiplicativeExpressionCase + switch p.rune() { + case '*': + kind = MultiplicativeExpressionMul + case '/': + kind = MultiplicativeExpressionDiv + case '%': + kind = MultiplicativeExpressionMod + default: + return r + } + + t := p.shift() + r = &MultiplicativeExpression{Case: kind, MultiplicativeExpression: r, Token: t, CastExpression: p.castExpression()} + } +} + +// [0], 6.5.6 Additive operators +// +// additive-expression: +// multiplicative-expression +// additive-expression + multiplicative-expression +// additive-expression - multiplicative-expression +func (p *parser) additiveExpression() (r *AdditiveExpression) { + r = &AdditiveExpression{Case: AdditiveExpressionMul, MultiplicativeExpression: p.multiplicativeExpression()} + for { + var kind AdditiveExpressionCase + switch p.rune() { + case '+': + kind = AdditiveExpressionAdd + case '-': + kind = AdditiveExpressionSub + default: + return r + } + + t := p.shift() + r = &AdditiveExpression{Case: kind, AdditiveExpression: r, Token: t, MultiplicativeExpression: p.multiplicativeExpression(), lexicalScope: p.declScope} + } +} + +// [0], 6.5.7 Bitwise shift operators +// +// shift-expression: +// additive-expression +// shift-expression << additive-expression +// shift-expression >> additive-expression +func (p *parser) shiftExpression() (r *ShiftExpression) { + r = &ShiftExpression{Case: ShiftExpressionAdd, AdditiveExpression: p.additiveExpression()} + for { + var kind ShiftExpressionCase + switch p.rune() { + case LSH: + kind = ShiftExpressionLsh + case RSH: + kind = ShiftExpressionRsh + default: + return r + } + + t := p.shift() + r = &ShiftExpression{Case: kind, ShiftExpression: r, Token: t, AdditiveExpression: p.additiveExpression()} + } +} + +// [0], 6.5.8 Relational operators +// +// relational-expression: +// shift-expression +// relational-expression < shift-expression +// relational-expression > shift-expression +// relational-expression <= shift-expression +// relational-expression >= shift-expression +func (p *parser) relationalExpression() (r *RelationalExpression) { + r = &RelationalExpression{Case: RelationalExpressionShift, ShiftExpression: p.shiftExpression()} + for { + var kind RelationalExpressionCase + switch p.rune() { + case '<': + kind = RelationalExpressionLt + case '>': + kind = RelationalExpressionGt + case LEQ: + kind = RelationalExpressionLeq + case GEQ: + kind = RelationalExpressionGeq + default: + return r + } + + t := p.shift() + r = &RelationalExpression{Case: kind, RelationalExpression: r, Token: t, ShiftExpression: p.shiftExpression()} + } +} + +// [0], 6.5.9 Equality operators +// +// equality-expression: +// relational-expression +// equality-expression == relational-expression +// equality-expression != relational-expression +func (p *parser) equalityExpression() (r *EqualityExpression) { + r = &EqualityExpression{Case: EqualityExpressionRel, RelationalExpression: p.relationalExpression()} + for { + var kind EqualityExpressionCase + switch p.rune() { + case EQ: + kind = EqualityExpressionEq + case NEQ: + kind = EqualityExpressionNeq + default: + return r + } + + t := p.shift() + r = &EqualityExpression{Case: kind, EqualityExpression: r, Token: t, RelationalExpression: p.relationalExpression()} + } +} + +// [0], 6.5.10 Bitwise AND operator +// +// AND-expression: +// equality-expression +// AND-expression & equality-expression +func (p *parser) andExpression() (r *AndExpression) { + r = &AndExpression{Case: AndExpressionEq, EqualityExpression: p.equalityExpression()} + for { + switch p.rune() { + case '&': + t := p.shift() + r = &AndExpression{Case: AndExpressionAnd, AndExpression: r, Token: t, EqualityExpression: p.equalityExpression()} + default: + return r + } + } +} + +// [0], 6.5.11 Bitwise exclusive OR operator +// +// exclusive-OR-expression: +// AND-expression +// exclusive-OR-expression ^ AND-expression +func (p *parser) exclusiveOrExpression() (r *ExclusiveOrExpression) { + r = &ExclusiveOrExpression{Case: ExclusiveOrExpressionAnd, AndExpression: p.andExpression()} + for { + switch p.rune() { + case '^': + t := p.shift() + r = &ExclusiveOrExpression{Case: ExclusiveOrExpressionXor, ExclusiveOrExpression: r, Token: t, AndExpression: p.andExpression()} + default: + return r + } + } +} + +// [0], 6.5.12 Bitwise inclusive OR operator +// +// inclusive-OR-expression: +// exclusive-OR-expression +// inclusive-OR-expression | exclusive-OR-expression +func (p *parser) inclusiveOrExpression() (r *InclusiveOrExpression) { + r = &InclusiveOrExpression{Case: InclusiveOrExpressionXor, ExclusiveOrExpression: p.exclusiveOrExpression()} + for { + switch p.rune() { + case '|': + t := p.shift() + r = &InclusiveOrExpression{Case: InclusiveOrExpressionOr, InclusiveOrExpression: r, Token: t, ExclusiveOrExpression: p.exclusiveOrExpression()} + default: + return r + } + } +} + +// [0], 6.5.13 Logical AND operator +// +// logical-AND-expression: +// inclusive-OR-expression +// logical-AND-expression && inclusive-OR-expression +func (p *parser) logicalAndExpression() (r *LogicalAndExpression) { + r = &LogicalAndExpression{Case: LogicalAndExpressionOr, InclusiveOrExpression: p.inclusiveOrExpression()} + for { + switch p.rune() { + case ANDAND: + t := p.shift() + r = &LogicalAndExpression{Case: LogicalAndExpressionLAnd, LogicalAndExpression: r, Token: t, InclusiveOrExpression: p.inclusiveOrExpression()} + default: + return r + } + } +} + +// [0], 6.5.14 Logical OR operator +// +// logical-OR-expression: +// logical-AND-expression +// logical-OR-expression || logical-AND-expression +func (p *parser) logicalOrExpression() (r *LogicalOrExpression) { + r = &LogicalOrExpression{Case: LogicalOrExpressionLAnd, LogicalAndExpression: p.logicalAndExpression()} + for { + switch p.rune() { + case OROR: + t := p.shift() + r = &LogicalOrExpression{Case: LogicalOrExpressionLOr, LogicalOrExpression: r, Token: t, LogicalAndExpression: p.logicalAndExpression()} + default: + return r + } + } +} + +// [0], 6.5.15 Conditional operator +// +// conditional-expression: +// logical-OR-expression +// logical-OR-expression ? expression : conditional-expression +func (p *parser) conditionalExpression() (r *ConditionalExpression) { + lo := p.logicalOrExpression() + var t, t2 Token + switch p.rune() { + case '?': + t = p.shift() + var e *Expression + switch p.rune() { + case ':': + if p.ctx.cfg.RejectMissingConditionalExpr { + p.err("expected expression") + } + default: + e = p.expression() + } + switch p.rune() { + case ':': + t2 = p.shift() + default: + p.err("expected :") + } + return &ConditionalExpression{Case: ConditionalExpressionCond, LogicalOrExpression: lo, Token: t, Expression: e, Token2: t2, ConditionalExpression: p.conditionalExpression()} + default: + return &ConditionalExpression{Case: ConditionalExpressionLOr, LogicalOrExpression: lo} + } +} + +// [0], 6.5.16 Assignment operators +// +// assignment-expression: +// conditional-expression +// unary-expression assignment-operator assignment-expression +// +// assignment-operator: one of +// = *= /= %= += -= <<= >>= &= ^= |= +func (p *parser) assignmentExpression() (r *AssignmentExpression) { + ce := p.conditionalExpression() + if ce == nil || ce.Case != ConditionalExpressionLOr { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + loe := ce.LogicalOrExpression + if loe == nil || loe.Case != LogicalOrExpressionLAnd { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + lae := loe.LogicalAndExpression + if lae == nil || lae.Case != LogicalAndExpressionOr { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + ioe := lae.InclusiveOrExpression + if ioe == nil || ioe.Case != InclusiveOrExpressionXor { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + eoe := ioe.ExclusiveOrExpression + if eoe == nil || eoe.Case != ExclusiveOrExpressionAnd { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + ae := eoe.AndExpression + if ae == nil || ae.Case != AndExpressionEq { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + ee := ae.EqualityExpression + if ee == nil || ee.Case != EqualityExpressionRel { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + re := ee.RelationalExpression + if re == nil || re.Case != RelationalExpressionShift { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + se := re.ShiftExpression + if se == nil || se.Case != ShiftExpressionAdd { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + adde := se.AdditiveExpression + if adde == nil || adde.Case != AdditiveExpressionMul { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + me := adde.MultiplicativeExpression + if me == nil || me.Case != MultiplicativeExpressionCast { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + cast := me.CastExpression + if cast == nil || cast.Case != CastExpressionUnary { + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + var kind AssignmentExpressionCase + switch p.rune() { + case '=': + kind = AssignmentExpressionAssign + case MULASSIGN: + kind = AssignmentExpressionMul + case DIVASSIGN: + kind = AssignmentExpressionDiv + case MODASSIGN: + kind = AssignmentExpressionMod + case ADDASSIGN: + kind = AssignmentExpressionAdd + case SUBASSIGN: + kind = AssignmentExpressionSub + case LSHASSIGN: + kind = AssignmentExpressionLsh + case RSHASSIGN: + kind = AssignmentExpressionRsh + case ANDASSIGN: + kind = AssignmentExpressionAnd + case XORASSIGN: + kind = AssignmentExpressionXor + case ORASSIGN: + kind = AssignmentExpressionOr + default: + return &AssignmentExpression{Case: AssignmentExpressionCond, ConditionalExpression: ce, lexicalScope: p.declScope} + } + + t := p.shift() + return &AssignmentExpression{Case: kind, UnaryExpression: cast.UnaryExpression, Token: t, AssignmentExpression: p.assignmentExpression(), lexicalScope: p.declScope} +} + +// [0], 6.5.17 Comma operator +// +// expression: +// assignment-expression +// expression , assignment-expression +func (p *parser) expression() (r *Expression) { + r = &Expression{Case: ExpressionAssign, AssignmentExpression: p.assignmentExpression()} + for { + switch p.rune() { + case ',': + t := p.shift() + r = &Expression{Case: ExpressionComma, Expression: r, Token: t, AssignmentExpression: p.assignmentExpression()} + default: + return r + } + } +} + +// [0], 6.6 Constant expressions +// +// constant-expression: +// conditional-expression +func (p *parser) constantExpression() (r *ConstantExpression) { + return &ConstantExpression{ConditionalExpression: p.conditionalExpression()} +} + +// [0], 6.7 Declarations +// +// declaration: +// declaration-specifiers init-declarator-list_opt attribute-specifier-list_opt ; +func (p *parser) declaration(ds *DeclarationSpecifiers, d *Declarator) (r *Declaration) { + defer func() { + if cs := p.block; cs != nil && r != nil { + cs.declarations = append(cs.declarations, r) + } + }() + + if ds == nil { + ds = p.declarationSpecifiers(nil, nil) + } + if ds == noDeclSpecs { + ds = nil + } + if d == nil { + switch p.rune() { + case ';': + p.typedefNameEnabled = true + return &Declaration{DeclarationSpecifiers: ds, Token: p.shift()} + } + } + + list := p.initDeclaratorList(d, ds.typedef()) + p.typedefNameEnabled = true + var t Token + switch p.rune() { + case ';': + t = p.shift() + default: + p.err("expected ;") + } + return &Declaration{DeclarationSpecifiers: ds, InitDeclaratorList: list, Token: t} +} + +// declaration-specifiers: +// storage-class-specifier declaration-specifiers_opt +// type-specifier declaration-specifiers_opt +// type-qualifier declaration-specifiers_opt +// function-specifier declaration-specifiers_opt +// alignment-specifier declaration-specifiers_opt +// attribute-specifier declaration-specifiers_opt +func (p *parser) declarationSpecifiers(extern, inline *bool) (r *DeclarationSpecifiers) { + switch p.rune() { + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL: + if extern != nil && p.rune() == EXTERN { + *extern = true + } + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersStorage, StorageClassSpecifier: p.storageClassSpecifier()} + if r.StorageClassSpecifier.Case == StorageClassSpecifierTypedef { + r.class = fTypedef + } + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} + case CONST, RESTRICT, VOLATILE: + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} + case INLINE, NORETURN: + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersFunc, FunctionSpecifier: p.functionSpecifier(inline)} + case ALIGNAS: + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} + case ATOMIC: + switch p.peek(false) { + case '(': + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} + default: + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} + } + case ATTRIBUTE: + r = &DeclarationSpecifiers{Case: DeclarationSpecifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} + default: + p.err("expected declaration-specifiers") + return nil + } + r0 := r + for prev := r; ; prev = prev.DeclarationSpecifiers { + switch p.rune() { + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL: + if extern != nil && p.rune() == EXTERN { + *extern = true + } + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersStorage, StorageClassSpecifier: p.storageClassSpecifier()} + if prev.DeclarationSpecifiers.StorageClassSpecifier.Case == StorageClassSpecifierTypedef { + r0.class |= fTypedef + } + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} + case CONST, RESTRICT, VOLATILE: + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} + case INLINE, NORETURN: + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersFunc, FunctionSpecifier: p.functionSpecifier(inline)} + case ALIGNAS: + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} + case ATOMIC: + switch p.peek(false) { + case '(': + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeSpec, TypeSpecifier: p.typeSpecifier()} + default: + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersTypeQual, TypeQualifier: p.typeQualifier()} + } + case ATTRIBUTE: + prev.DeclarationSpecifiers = &DeclarationSpecifiers{Case: DeclarationSpecifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} + default: + return r + } + } +} + +// init-declarator-list: +// init-declarator +// init-declarator-list , attribute-specifier-list_opt init-declarator +func (p *parser) initDeclaratorList(d *Declarator, isTypedefName bool) (r *InitDeclaratorList) { + r = &InitDeclaratorList{InitDeclarator: p.initDeclarator(d, isTypedefName)} + for prev := r; ; prev = prev.InitDeclaratorList { + switch p.rune() { + case ',': + t := p.shift() + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + prev.InitDeclaratorList = &InitDeclaratorList{Token: t, AttributeSpecifierList: attr, InitDeclarator: p.initDeclarator(nil, isTypedefName)} + default: + return r + } + } +} + +func (p *parser) attributeSpecifierListOpt() (r *AttributeSpecifierList) { + if p.rune() == ATTRIBUTE { + r = p.attributeSpecifierList() + } + return r +} + +// init-declarator: +// declarator attribute-specifier-list_opt +// declarator attribute-specifier-list_opt = initializer +func (p *parser) initDeclarator(d *Declarator, isTypedefName bool) *InitDeclarator { + if d == nil { + d = p.declarator(true, isTypedefName, nil) + } + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + switch p.rune() { + case '=': + t := p.shift() + return &InitDeclarator{Case: InitDeclaratorInit, Declarator: d, AttributeSpecifierList: attr, Token: t, Initializer: p.initializer(nil)} + } + + return &InitDeclarator{Case: InitDeclaratorDecl, Declarator: d, AttributeSpecifierList: attr} +} + +// [0], 6.7.1 Storage-class specifiers +// +// storage-class-specifier: +// typedef +// extern +// static +// auto +// register +func (p *parser) storageClassSpecifier() *StorageClassSpecifier { + var kind StorageClassSpecifierCase + switch p.rune() { + case TYPEDEF: + kind = StorageClassSpecifierTypedef + case EXTERN: + kind = StorageClassSpecifierExtern + case STATIC: + kind = StorageClassSpecifierStatic + case AUTO: + kind = StorageClassSpecifierAuto + case REGISTER: + kind = StorageClassSpecifierRegister + case THREADLOCAL: + kind = StorageClassSpecifierThreadLocal + default: + p.err("expected storage-class-specifier") + return nil + } + + return &StorageClassSpecifier{Case: kind, Token: p.shift()} +} + +// [0], 6.7.2 Type specifiers +// +// type-specifier: +// void +// char +// short +// int +// long +// float +// __fp16 +// __float80 +// double +// signed +// unsigned +// _Bool +// _Complex +// _Float128 +// struct-or-union-specifier +// enum-specifier +// typedef-name +// typeof ( expression ) +// typeof ( type-name ) +// atomic-type-specifier +// _Frac +// _Sat +// _Accum +// _Float32 +func (p *parser) typeSpecifier() *TypeSpecifier { + var kind TypeSpecifierCase + switch p.rune() { + case VOID: + kind = TypeSpecifierVoid + case CHAR: + kind = TypeSpecifierChar + case SHORT: + kind = TypeSpecifierShort + case INT: + kind = TypeSpecifierInt + case INT8: + kind = TypeSpecifierInt8 + case INT16: + kind = TypeSpecifierInt16 + case INT32: + kind = TypeSpecifierInt32 + case INT64: + kind = TypeSpecifierInt64 + case INT128: + kind = TypeSpecifierInt128 + case LONG: + kind = TypeSpecifierLong + case FLOAT: + kind = TypeSpecifierFloat + case FLOAT16: + kind = TypeSpecifierFloat16 + case FLOAT80: + kind = TypeSpecifierFloat80 + case FLOAT32: + kind = TypeSpecifierFloat32 + case FLOAT32X: + kind = TypeSpecifierFloat32x + case FLOAT64: + kind = TypeSpecifierFloat64 + case FLOAT64X: + kind = TypeSpecifierFloat64x + case FLOAT128: + kind = TypeSpecifierFloat128 + case DECIMAL32: + kind = TypeSpecifierDecimal32 + case DECIMAL64: + kind = TypeSpecifierDecimal64 + case DECIMAL128: + kind = TypeSpecifierDecimal128 + case DOUBLE: + kind = TypeSpecifierDouble + case SIGNED: + kind = TypeSpecifierSigned + case UNSIGNED: + kind = TypeSpecifierUnsigned + case BOOL: + kind = TypeSpecifierBool + case COMPLEX: + kind = TypeSpecifierComplex + case FRACT: + kind = TypeSpecifierFract + case SAT: + kind = TypeSpecifierSat + case ACCUM: + kind = TypeSpecifierAccum + case TYPEDEFNAME: + kind = TypeSpecifierTypedefName + case STRUCT, UNION: + r := &TypeSpecifier{Case: TypeSpecifierStructOrUnion, StructOrUnionSpecifier: p.structOrUnionSpecifier()} + p.typedefNameEnabled = false + return r + case ENUM: + r := &TypeSpecifier{Case: TypeSpecifierEnum, EnumSpecifier: p.enumSpecifier()} + p.typedefNameEnabled = false + return r + case TYPEOF: + var t, t2, t3 Token + t = p.shift() + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + switch p.rune() { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE, + ALIGNAS: + typ := p.typeName() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &TypeSpecifier{Case: TypeSpecifierTypeofType, Token: t, Token2: t2, TypeName: typ, Token3: t3} + default: + e := p.expression() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &TypeSpecifier{Case: TypeSpecifierTypeofExpr, Token: t, Token2: t2, Expression: e, Token3: t3} + } + case ATOMIC: + return &TypeSpecifier{Case: TypeSpecifierAtomic, AtomicTypeSpecifier: p.atomicTypeSpecifier()} + default: + p.err("expected type-specifier") + return nil + } + + p.typedefNameEnabled = false + return &TypeSpecifier{Case: kind, Token: p.shift(), resolvedIn: p.resolvedIn} +} + +// [0], 6.7.2.1 Structure and union specifiers +// +// struct-or-union-specifier: +// struct-or-union attribute-specifier-list_opt identifier_opt { struct-declaration-list } +// struct-or-union attribute-specifier-list_opt identifier +func (p *parser) structOrUnionSpecifier() *StructOrUnionSpecifier { + switch p.rune() { + case STRUCT, UNION: + default: + p.err("expected struct-or-union-specifier") + return nil + } + + sou := p.structOrUnion() + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + var t, t2, t3 Token + switch p.rune() { + case IDENTIFIER: + t = p.shift() + if p.rune() != '{' { + return &StructOrUnionSpecifier{Case: StructOrUnionSpecifierTag, StructOrUnion: sou, AttributeSpecifierList: attr, Token: t, lexicalScope: p.declScope} + } + + fallthrough + case '{': + maxAlign := p.ctx.maxAlign + p.openScope(true) + p.typedefNameEnabled = true + p.resolveScope = p.declScope.Parent() + t2 = p.shift() + var list *StructDeclarationList + switch p.peek(false) { + case '}': + if p.ctx.cfg.RejectEmptyStructs { + p.err("expected struct-declarator-list") + } + default: + list = p.structDeclarationList() + } + p.closeScope() + switch p.rune() { + case '}': + t3 = p.shift() + default: + p.err("expected }") + } + r := &StructOrUnionSpecifier{Case: StructOrUnionSpecifierDef, StructOrUnion: sou, AttributeSpecifierList: attr, Token: t, Token2: t2, StructDeclarationList: list, Token3: t3, lexicalScope: p.declScope, maxAlign: maxAlign} + if t.Value != 0 { + p.declScope.declare(t.Value, r) + } + return r + default: + p.err("expected identifier or {") + return nil + } +} + +// struct-or-union: +// struct +// union +func (p *parser) structOrUnion() *StructOrUnion { + var kind StructOrUnionCase + switch p.rune() { + case STRUCT: + kind = StructOrUnionStruct + case UNION: + kind = StructOrUnionUnion + default: + p.err("expected struct-or-union") + return nil + } + + p.typedefNameEnabled = false + return &StructOrUnion{Case: kind, Token: p.shift()} +} + +// struct-declaration-list: +// struct-declaration +// struct-declaration-list struct-declaration +func (p *parser) structDeclarationList() (r *StructDeclarationList) { + r = &StructDeclarationList{StructDeclaration: p.structDeclaration()} + for prev := r; ; prev = prev.StructDeclarationList { + switch p.rune() { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE, + ALIGNAS: + prev.StructDeclarationList = &StructDeclarationList{StructDeclaration: p.structDeclaration()} + case ';': + p.shift() + if p.ctx.cfg.RejectEmptyFields { + p.err("expected struct-declaration") + } + default: + return r + } + } +} + +// struct-declaration: +// specifier-qualifier-list struct-declarator-list ; +func (p *parser) structDeclaration() (r *StructDeclaration) { + if p.rune() == ';' { + if p.ctx.cfg.RejectEmptyStructDeclaration { + p.err("expected struct-declaration") + } + return &StructDeclaration{Empty: true, Token: p.shift()} + } + sql := p.specifierQualifierList() + r = &StructDeclaration{SpecifierQualifierList: sql} + switch p.rune() { + case ';': + if p.ctx.cfg.RejectAnonymousFields { + p.err("expected struct-declarator") + } + default: + r.StructDeclaratorList = p.structDeclaratorList(r) + } + var t Token + p.typedefNameEnabled = true + switch p.rune() { + case '}': + if p.ctx.cfg.RejectMissingFinalStructFieldSemicolon { + p.err0(false, "expected ;") + } + case ';': + t = p.shift() + default: + p.err("expected ;") + } + r.Token = t + return r +} + +// specifier-qualifier-list: +// type-specifier specifier-qualifier-list_opt +// type-qualifier specifier-qualifier-list_opt +// alignment-specifier-qualifier-list_opt +func (p *parser) specifierQualifierList() (r *SpecifierQualifierList) { + switch p.rune() { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: + r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} + case CONST, RESTRICT, VOLATILE: + r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} + case ALIGNAS: + r = &SpecifierQualifierList{Case: SpecifierQualifierListAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} + case ATOMIC: + switch p.peek(false) { + case '(': + r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} + default: + r = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} + } + case ATTRIBUTE: + r = &SpecifierQualifierList{Case: SpecifierQualifierListAttribute, AttributeSpecifier: p.attributeSpecifier()} + default: + p.err("expected specifier-qualifier-list: %s", tokName(p.rune())) + return nil + } + for prev := r; ; prev = prev.SpecifierQualifierList { + switch p.rune() { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF: + prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} + case CONST, RESTRICT, VOLATILE: + prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} + case ALIGNAS: + prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListAlignSpec, AlignmentSpecifier: p.alignmentSpecifier()} + case ATOMIC: + switch p.peek(false) { + case '(': + prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeSpec, TypeSpecifier: p.typeSpecifier()} + default: + prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListTypeQual, TypeQualifier: p.typeQualifier()} + } + case ATTRIBUTE: + prev.SpecifierQualifierList = &SpecifierQualifierList{Case: SpecifierQualifierListAttribute, AttributeSpecifier: p.attributeSpecifier()} + default: + return r + } + } +} + +// struct-declarator-list: +// struct-declarator +// struct-declarator-list , struct-declarator +func (p *parser) structDeclaratorList(decl *StructDeclaration) (r *StructDeclaratorList) { + r = &StructDeclaratorList{StructDeclarator: p.structDeclarator(decl)} + for prev := r; ; prev = prev.StructDeclaratorList { + switch p.rune() { + case ',': + t := p.shift() + prev.StructDeclaratorList = &StructDeclaratorList{Token: t, StructDeclarator: p.structDeclarator(decl)} + default: + return r + } + } +} + +// struct-declarator: +// declarator +// declarator_opt : constant-expression attribute-specifier-list_opt +func (p *parser) structDeclarator(decl *StructDeclaration) (r *StructDeclarator) { + var d *Declarator + if p.rune() != ':' { + d = p.declarator(false, false, nil) + } + + switch p.rune() { + case ':': + t := p.shift() + r = &StructDeclarator{Case: StructDeclaratorBitField, Declarator: d, Token: t, ConstantExpression: p.constantExpression(), decl: decl} + r.AttributeSpecifierList = p.attributeSpecifierListOpt() + // if r.AttributeSpecifierList != nil { + // trc("%v: ATTRS", r.AttributeSpecifierList.Position()) + // } + default: + r = &StructDeclarator{Case: StructDeclaratorDecl, Declarator: d, decl: decl} + } + if d != nil { + p.declScope.declare(d.Name(), r) + } + return r +} + +// [0], 6.7.2.2 Enumeration specifiers +// +// enum-specifier: +// enum attribute-specifier-list_opt identifier_opt { enumerator-list } +// enum attribute-specifier-list_opt identifier_opt { enumerator-list , } +// enum attribute-specifier-list_opt identifier +func (p *parser) enumSpecifier() *EnumSpecifier { + if p.rune() != ENUM { + p.err("expected enum") + return nil + } + + var t, t2, t3, t4, t5 Token + p.typedefNameEnabled = false + t = p.shift() + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + if p.rune() == IDENTIFIER { + t2 = p.shift() + if p.rune() != '{' { + return &EnumSpecifier{Case: EnumSpecifierTag, AttributeSpecifierList: attr, Token: t, Token2: t2, lexicalScope: p.declScope} + } + } + + if p.rune() != '{' { + p.err("expected identifier or {") + return nil + } + + p.typedefNameEnabled = false + t3 = p.shift() + list := p.enumeratorList() + if p.rune() == ',' { + t4 = p.shift() + } + + switch p.rune() { + case '}': + t5 = p.shift() + default: + p.err("expected }") + } + r := &EnumSpecifier{Case: EnumSpecifierDef, AttributeSpecifierList: attr, Token: t, Token2: t2, Token3: t3, EnumeratorList: list, Token4: t4, Token5: t5, lexicalScope: p.declScope} + if t2.Value != 0 { + p.declScope.declare(t2.Value, r) + } + return r +} + +// enumerator-list: +// enumerator +// enumerator-list , enumerator +func (p *parser) enumeratorList() *EnumeratorList { + r := &EnumeratorList{Enumerator: p.enumerator()} + for prev := r; ; prev = prev.EnumeratorList { + switch p.rune() { + case ',': + if p.peek(false) == '}' { + return r + } + + t := p.shift() + prev.EnumeratorList = &EnumeratorList{Token: t, Enumerator: p.enumerator()} + default: + return r + } + } +} + +// enumerator: +// enumeration-constant attribute-specifier-list_opt +// enumeration-constant attribute-specifier-list_opt = constant-expression +func (p *parser) enumerator() (r *Enumerator) { + if p.rune() != IDENTIFIER { + p.err("expected enumeration-constant") + return nil + } + + t := p.shift() + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + if p.rune() != '=' { + r = &Enumerator{Case: EnumeratorIdent, Token: t, AttributeSpecifierList: attr, lexicalScope: p.declScope} + p.declScope.declare(t.Value, r) + return r + } + + t2 := p.shift() + r = &Enumerator{Case: EnumeratorExpr, Token: t, AttributeSpecifierList: attr, Token2: t2, ConstantExpression: p.constantExpression(), lexicalScope: p.declScope} + p.declScope.declare(t.Value, r) + return r +} + +// [2], 6.7.2.4 Atomic type specifiers +// +// atomic-type-specifier: +// _Atomic ( type-name ) +func (p *parser) atomicTypeSpecifier() *AtomicTypeSpecifier { + if p.rune() != ATOMIC { + p.err("expected _Atomic") + return nil + } + + t := p.shift() + var t2, t3 Token + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + typ := p.typeName() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &AtomicTypeSpecifier{Token: t, Token2: t2, TypeName: typ, Token3: t3} +} + +// [0], 6.7.3 Type qualifiers +// +// type-qualifier: +// const +// restrict +// volatile +// _Atomic +func (p *parser) typeQualifier() *TypeQualifier { + switch p.rune() { + case CONST: + return &TypeQualifier{Case: TypeQualifierConst, Token: p.shift()} + case RESTRICT: + return &TypeQualifier{Case: TypeQualifierRestrict, Token: p.shift()} + case VOLATILE: + return &TypeQualifier{Case: TypeQualifierVolatile, Token: p.shift()} + case ATOMIC: + return &TypeQualifier{Case: TypeQualifierAtomic, Token: p.shift()} + default: + p.err("expected type-qualifier") + return nil + } +} + +// [0], 6.7.4 Function specifiers +// +// function-specifier: +// inline +// _Noreturn +func (p *parser) functionSpecifier(inline *bool) *FunctionSpecifier { + switch p.rune() { + case INLINE: + if inline != nil { + *inline = true + } + return &FunctionSpecifier{Case: FunctionSpecifierInline, Token: p.shift()} + case NORETURN: + return &FunctionSpecifier{Case: FunctionSpecifierNoreturn, Token: p.shift()} + default: + p.err("expected function-specifier") + return nil + } +} + +// [0], 6.7.5 Declarators +// +// declarator: +// pointer_opt direct-declarator attribute-specifier-list_opt +func (p *parser) declarator(declare, isTypedefName bool, ptr *Pointer) *Declarator { + if ptr == nil && (p.rune() == '*' || p.rune() == '^') { + ptr = p.pointer() + } + r := &Declarator{IsTypedefName: isTypedefName, Pointer: ptr, DirectDeclarator: p.directDeclarator(nil)} + r.AttributeSpecifierList = p.attributeSpecifierListOpt() + // if r.AttributeSpecifierList != nil { + // trc("%v: ATTRS", r.AttributeSpecifierList.Position()) + // } + if declare { + p.declScope.declare(r.Name(), r) + } + return r +} + +// [2], 6.7.5 Alignment specifier +// +// alignment-specifier: +// _Alignas ( type-name ) +// _Alignas ( constant-expression ) +func (p *parser) alignmentSpecifier() *AlignmentSpecifier { + if p.rune() != ALIGNAS { + p.err("expected _Alignas") + return nil + } + + t := p.shift() + var t2, t3 Token + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + switch p.rune() { + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE, + ALIGNAS: + typ := p.typeName() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &AlignmentSpecifier{Case: AlignmentSpecifierAlignasType, Token: t, Token2: t2, TypeName: typ, Token3: t3} + default: + e := p.constantExpression() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &AlignmentSpecifier{Case: AlignmentSpecifierAlignasExpr, Token: t, Token2: t2, ConstantExpression: e, Token3: t3} + } +} + +// direct-declarator: +// identifier asm_opt +// ( attribute-specifier-list_opt declarator ) +// direct-declarator [ type-qualifier-list_opt assignment-expression_opt ] +// direct-declarator [ static type-qualifier-list_opt assignment-expression ] +// direct-declarator [ type-qualifier-list static assignment-expression ] +// direct-declarator [ type-qualifier-list_opt * ] +// direct-declarator ( parameter-type-list ) +// direct-declarator ( identifier-list_opt ) +func (p *parser) directDeclarator(d *DirectDeclarator) (r *DirectDeclarator) { + switch { + case d != nil: + r = d + default: + switch p.rune() { + case IDENTIFIER: + t := p.shift() + var a *Asm + if p.rune() == ASM { + a = p.asm() + } + r = &DirectDeclarator{Case: DirectDeclaratorIdent, Token: t, Asm: a, lexicalScope: p.declScope} + case '(': + t := p.shift() + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + d := p.declarator(false, false, nil) + var t2 Token + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &DirectDeclarator{Case: DirectDeclaratorDecl, Token: t, AttributeSpecifierList: attr, Declarator: d, Token2: t2, lexicalScope: p.declScope} + default: + p.err("expected direct-declarator") + return nil + } + } + + var t, t2, t3 Token + for { + var e *AssignmentExpression + switch p.rune() { + case '[': + t = p.shift() + switch p.rune() { + case ']': + t2 = p.shift() + r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, Token2: t2, lexicalScope: p.declScope} + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: // type-qualifier + list := p.typeQualifierList() + switch p.rune() { + case STATIC: + t2 = p.shift() + e = p.assignmentExpression() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectDeclarator{Case: DirectDeclaratorArrStatic, DirectDeclarator: r, Token: t, TypeQualifiers: list, Token2: t2, AssignmentExpression: e, Token3: t3, lexicalScope: p.declScope} + case ']': + r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, TypeQualifiers: list, Token2: p.shift(), lexicalScope: p.declScope} + case '*': + switch p.peek(false) { + case ']': + t2 = p.shift() + r = &DirectDeclarator{Case: DirectDeclaratorStar, DirectDeclarator: r, Token: t, TypeQualifiers: list, Token2: t2, Token3: p.shift(), lexicalScope: p.declScope} + default: + e = p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2, lexicalScope: p.declScope} + } + default: + e = p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2, lexicalScope: p.declScope} + } + case STATIC: + t2 := p.shift() + var list *TypeQualifiers + switch p.peek(false) { + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list = p.typeQualifierList() + } + e := p.assignmentExpression() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectDeclarator{Case: DirectDeclaratorStaticArr, DirectDeclarator: r, Token: t, Token2: t2, TypeQualifiers: list, AssignmentExpression: e, Token3: t3, lexicalScope: p.declScope} + case '*': + if p.peek(false) == ']' { + t2 = p.shift() + r = &DirectDeclarator{Case: DirectDeclaratorStar, DirectDeclarator: r, Token: t, Token2: t2, Token3: p.shift(), lexicalScope: p.declScope} + break + } + + fallthrough + default: + e = p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectDeclarator{Case: DirectDeclaratorArr, DirectDeclarator: r, Token: t, AssignmentExpression: e, Token2: t2, lexicalScope: p.declScope} + } + case '(': + p.openScope(false) + p.typedefNameEnabled = true + t = p.shift() + paramScope := p.declScope + switch p.rune() { + case IDENTIFIER: + list := p.identifierList() + p.closeScope() + p.typedefNameEnabled = true + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &DirectDeclarator{Case: DirectDeclaratorFuncIdent, DirectDeclarator: r, Token: t, IdentifierList: list, Token2: t2, paramScope: paramScope, lexicalScope: p.declScope} + case ')': + p.closeScope() + p.typedefNameEnabled = true + r = &DirectDeclarator{Case: DirectDeclaratorFuncIdent, DirectDeclarator: r, Token: t, Token2: p.shift(), paramScope: paramScope, lexicalScope: p.declScope} + default: + list := p.parameterTypeList() + p.closeScope() + p.typedefNameEnabled = true + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &DirectDeclarator{Case: DirectDeclaratorFuncParam, DirectDeclarator: r, Token: t, ParameterTypeList: list, Token2: t2, paramScope: paramScope, lexicalScope: p.declScope} + } + default: + return r + } + } +} + +// pointer: +// * type-qualifier-list_opt +// * type-qualifier-list_opt pointer +// ^ type-qualifier-list_opt +func (p *parser) pointer() (r *Pointer) { + if p.rune() == '^' { + t := p.shift() + var list *TypeQualifiers + switch p.rune() { + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list = p.typeQualifierList() + } + + return &Pointer{Case: PointerBlock, Token: t, TypeQualifiers: list} + } + + if p.rune() != '*' { + p.err("expected * or ^") + return nil + } + + t := p.shift() + var list *TypeQualifiers + switch p.rune() { + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list = p.typeQualifierList() + } + + switch p.rune() { + case '*': + return &Pointer{Case: PointerPtr, Token: t, TypeQualifiers: list, Pointer: p.pointer()} + default: + return &Pointer{Case: PointerTypeQual, Token: t, TypeQualifiers: list} + } +} + +// type-qualifier-list: +// type-qualifier +// attribute-specifier +// type-qualifier-list type-qualifier +// type-qualifier-list attribute-specifier +func (p *parser) typeQualifierList() (r *TypeQualifiers) { + switch p.rune() { + case ATTRIBUTE: + r = &TypeQualifiers{Case: TypeQualifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} + default: + r = &TypeQualifiers{Case: TypeQualifiersTypeQual, TypeQualifier: p.typeQualifier()} + } + for prev := r; ; prev = prev.TypeQualifiers { + switch p.rune() { + case ATTRIBUTE: + prev.TypeQualifiers = &TypeQualifiers{Case: TypeQualifiersAttribute, AttributeSpecifier: p.attributeSpecifier()} + case CONST, RESTRICT, VOLATILE, ATOMIC: + prev.TypeQualifiers = &TypeQualifiers{TypeQualifier: p.typeQualifier()} + default: + return r + } + } +} + +// parameter-type-list: +// parameter-list +// parameter-list , ... +func (p *parser) parameterTypeList() *ParameterTypeList { + list := p.parameterList() + switch p.rune() { + case ',': + t := p.shift() + var t2 Token + switch p.rune() { + case DDD: + t2 = p.shift() + default: + p.err("expected ...") + } + return &ParameterTypeList{Case: ParameterTypeListVar, ParameterList: list, Token: t, Token2: t2} + default: + return &ParameterTypeList{Case: ParameterTypeListList, ParameterList: list} + } +} + +// parameter-list: +// parameter-declaration +// parameter-list , parameter-declaration +func (p *parser) parameterList() (r *ParameterList) { + r = &ParameterList{ParameterDeclaration: p.parameterDeclaration()} + for prev := r; ; prev = prev.ParameterList { + switch p.rune() { + case ';': + if p.ctx.cfg.RejectParamSemicolon { + p.err0(false, "expected ,") + } + fallthrough + case ',': + if p.peek(false) == DDD { + return r + } + + p.typedefNameEnabled = true + t := p.shift() + prev.ParameterList = &ParameterList{Token: t, ParameterDeclaration: p.parameterDeclaration()} + default: + return r + } + } +} + +// parameter-declaration: +// declaration-specifiers declarator attribute-specifier-list_opt +// declaration-specifiers abstract-declarator_opt +func (p *parser) parameterDeclaration() *ParameterDeclaration { + ds := p.declarationSpecifiers(nil, nil) + switch p.rune() { + case ',', ')': + r := &ParameterDeclaration{Case: ParameterDeclarationAbstract, DeclarationSpecifiers: ds} + return r + default: + switch x := p.declaratorOrAbstractDeclarator(ds.typedef()).(type) { + case *AbstractDeclarator: + return &ParameterDeclaration{Case: ParameterDeclarationAbstract, DeclarationSpecifiers: ds, AbstractDeclarator: x} + case *Declarator: + p.declScope.declare(x.Name(), x) + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + return &ParameterDeclaration{Case: ParameterDeclarationDecl, DeclarationSpecifiers: ds, Declarator: x, AttributeSpecifierList: attr} + default: + panic(internalError()) + } + } +} + +func (p *parser) declaratorOrAbstractDeclarator(isTypedefName bool) (r Node) { + var ptr *Pointer + switch p.rune() { + case '*', '^': + ptr = p.pointer() + } + switch p.rune() { + case IDENTIFIER: + return p.declarator(false, isTypedefName, ptr) + case '[': + return p.abstractDeclarator(ptr) + case '(': + switch p.peek(true) { + case ')': + t := p.shift() + t2 := p.shift() + return &AbstractDeclarator{ + Case: AbstractDeclaratorDecl, + Pointer: ptr, + DirectAbstractDeclarator: p.directAbstractDeclarator( + &DirectAbstractDeclarator{ + Case: DirectAbstractDeclaratorFunc, + Token: t, + Token2: t2, + }, + ), + } + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, + VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + CONST, RESTRICT, VOLATILE, + INLINE, NORETURN, ATTRIBUTE, + ALIGNAS: + p.openScope(false) + paramScope := p.declScope + p.typedefNameEnabled = true + t := p.shift() + list := p.parameterTypeList() + p.closeScope() + p.typedefNameEnabled = true + var t2 Token + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + return &AbstractDeclarator{ + Case: AbstractDeclaratorDecl, + Pointer: ptr, + DirectAbstractDeclarator: p.directAbstractDeclarator( + &DirectAbstractDeclarator{ + Case: DirectAbstractDeclaratorFunc, + Token: t, + ParameterTypeList: list, + Token2: t2, + paramScope: paramScope, + }, + ), + } + } + + t := p.shift() + switch x := p.declaratorOrAbstractDeclarator(isTypedefName).(type) { + case *AbstractDeclarator: + var t2 Token + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + return &AbstractDeclarator{ + Case: AbstractDeclaratorDecl, + Pointer: ptr, + DirectAbstractDeclarator: p.directAbstractDeclarator( + &DirectAbstractDeclarator{ + Case: DirectAbstractDeclaratorDecl, + Token: t, + AbstractDeclarator: x, + Token2: t2, + }, + ), + } + case *Declarator: + var t2 Token + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + return &Declarator{ + Pointer: ptr, + DirectDeclarator: p.directDeclarator( + &DirectDeclarator{ + Case: DirectDeclaratorDecl, + Token: t, + Declarator: x, + Token2: t2, + }, + ), + } + default: + panic(internalError()) + } + case ')', ',': + return p.abstractDeclarator(ptr) + default: + p.err("unexpected %s", p.tok.Value) + return p.abstractDeclarator(ptr) + } +} + +// identifier-list: +// identifier +// identifier-list , identifier +func (p *parser) identifierList() (r *IdentifierList) { + switch p.rune() { + case IDENTIFIER: + r = &IdentifierList{Token: p.shift(), lexicalScope: p.declScope} + default: + p.err("expected identifier") + return nil + } + + for prev := r; p.rune() == ','; prev = prev.IdentifierList { + t := p.shift() + var t2 Token + switch p.rune() { + case IDENTIFIER: + t2 = p.shift() + default: + p.err("expected identifier") + } + prev.IdentifierList = &IdentifierList{Token: t, Token2: t2, lexicalScope: p.declScope} + } + return r +} + +// [0], 6.7.6 Type names +// +// type-name: +// specifier-qualifier-list abstract-declarator_opt +func (p *parser) typeName() *TypeName { + p.typedefNameEnabled = true + list := p.specifierQualifierList() + switch p.rune() { + case ')', ',': + return &TypeName{SpecifierQualifierList: list} + case '*', '(', '[': + return &TypeName{SpecifierQualifierList: list, AbstractDeclarator: p.abstractDeclarator(nil)} + default: + p.err("expected ) or * or ( or [ or ,") + return &TypeName{SpecifierQualifierList: list} + } +} + +// abstract-declarator: +// pointer +// pointer_opt direct-abstract-declarator +func (p *parser) abstractDeclarator(ptr *Pointer) *AbstractDeclarator { + if ptr == nil && (p.rune() == '*' || p.rune() == '^') { + ptr = p.pointer() + } + switch p.rune() { + case '[', '(': + return &AbstractDeclarator{Case: AbstractDeclaratorDecl, Pointer: ptr, DirectAbstractDeclarator: p.directAbstractDeclarator(nil)} + default: + return &AbstractDeclarator{Case: AbstractDeclaratorPtr, Pointer: ptr} + } +} + +// direct-abstract-declarator: +// ( abstract-declarator ) +// direct-abstract-declarator_opt [ type-qualifier-list_opt assignment-expression_opt ] +// direct-abstract-declarator_opt [ static type-qualifier-list_opt assignment-expression ] +// direct-abstract-declarator_opt [ type-qualifier-list static assignment-expression ] +// direct-abstract-declarator_opt [ * ] +// direct-abstract-declarator_opt ( parameter-type-list_opt ) +func (p *parser) directAbstractDeclarator(d *DirectAbstractDeclarator) (r *DirectAbstractDeclarator) { + var t, t2, t3 Token + switch { + case d != nil: + r = d + default: + switch p.rune() { + case '[': + t = p.shift() + switch p.rune() { + case '*': + t2 = p.shift() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStar, Token: t, Token2: t2, Token3: t3} + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list := p.typeQualifierList() + switch p.rune() { + case STATIC: + t2 = p.shift() + e := p.assignmentExpression() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStatic, Token: t, TypeQualifiers: list, Token2: t2, AssignmentExpression: e, Token3: t3} + default: + e := p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2} + } + case STATIC: + t2 = p.shift() + var list *TypeQualifiers + switch p.rune() { + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list = p.typeQualifierList() + } + e := p.assignmentExpression() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorStaticArr, Token: t, Token2: t2, TypeQualifiers: list, AssignmentExpression: e, Token3: t3} + case ']': + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, Token: t, Token2: p.shift()} + default: + e := p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, Token: t, AssignmentExpression: e, Token2: t2} + } + case '(': + switch p.peek(true) { + case ')': + t := p.shift() + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, Token: t, Token2: p.shift()} + case VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + ATTRIBUTE, CONST, RESTRICT, VOLATILE, + ALIGNAS: + p.openScope(false) + paramScope := p.declScope + p.typedefNameEnabled = true + t = p.shift() + list := p.parameterTypeList() + p.closeScope() + p.typedefNameEnabled = true + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, Token: t, ParameterTypeList: list, Token2: t2, paramScope: paramScope} + default: + p.openScope(false) + paramScope := p.declScope + p.typedefNameEnabled = true + t = p.shift() + d := p.abstractDeclarator(nil) + p.closeScope() + p.typedefNameEnabled = true + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorDecl, Token: t, AbstractDeclarator: d, Token2: t2, paramScope: paramScope} + } + default: + panic(internalError()) + } + } + + for { + switch p.rune() { + case '(': + if p.peek(false) == ')' { + t = p.shift() + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, DirectAbstractDeclarator: r, Token: t, Token2: p.shift()} + break + } + + p.openScope(false) + p.typedefNameEnabled = true + t = p.shift() + paramScope := p.declScope + list := p.parameterTypeList() + p.closeScope() + p.typedefNameEnabled = true + switch p.rune() { + case ')': + t2 = p.shift() + default: + p.err("expected )") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorFunc, DirectAbstractDeclarator: r, Token: t, ParameterTypeList: list, Token2: t2, paramScope: paramScope} + case '[': + t = p.shift() + switch p.rune() { + case '*': + t2 = p.shift() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStar, DirectAbstractDeclarator: r, Token: t, Token2: t2, Token3: t3} + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list := p.typeQualifierList() + switch p.rune() { + case STATIC: + t2 = p.shift() + e := p.assignmentExpression() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArrStatic, DirectAbstractDeclarator: r, Token: t, TypeQualifiers: list, Token2: t2, AssignmentExpression: e, Token3: t3} + default: + e := p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, DirectAbstractDeclarator: r, Token: t, TypeQualifiers: list, AssignmentExpression: e, Token2: t2} + } + case STATIC: + t2 = p.shift() + var list *TypeQualifiers + switch p.rune() { + case ATTRIBUTE, CONST, RESTRICT, VOLATILE, ATOMIC: + list = p.typeQualifierList() + } + e := p.assignmentExpression() + switch p.rune() { + case ']': + t3 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorStaticArr, DirectAbstractDeclarator: r, Token: t, Token2: t2, TypeQualifiers: list, AssignmentExpression: e, Token3: t3} + case ']': + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, DirectAbstractDeclarator: r, Token: t, Token2: p.shift()} + default: + e := p.assignmentExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + r = &DirectAbstractDeclarator{Case: DirectAbstractDeclaratorArr, DirectAbstractDeclarator: r, Token: t, AssignmentExpression: e, Token2: t2} + } + default: + return r + } + } +} + +// [0], 6.7.8 Initialization +// +// initializer: +// assignment-expression +// { initializer-list } +// { initializer-list , } +func (p *parser) initializer(parent *Initializer) *Initializer { + switch p.rune() { + case '{': + t := p.shift() + if p.peek(false) == '}' { + if p.ctx.cfg.RejectEmptyInitializerList { + p.err("expected initializer-list") + } + return &Initializer{Case: InitializerInitList, Token: t, Token3: p.shift()} + } + + r := &Initializer{Case: InitializerInitList, Token: t, parent: parent} + r.InitializerList = p.initializerList(r) + if p.rune() == ',' { + r.Token2 = p.shift() + } + switch p.rune() { + case '}': + r.Token3 = p.shift() + default: + p.err("expected }") + } + return r + default: + return &Initializer{Case: InitializerExpr, AssignmentExpression: p.assignmentExpression(), parent: parent} + } +} + +// initializer-list: +// designation_opt initializer +// initializer-list , designation_opt initializer +func (p *parser) initializerList(parent *Initializer) (r *InitializerList) { + var d *Designation + switch p.rune() { + case '[', '.': + d = p.designation() + case IDENTIFIER: + if p.peek(false) == ':' { + d = p.designation() + } + } + r = &InitializerList{Designation: d, Initializer: p.initializer(parent)} + for prev := r; ; prev = prev.InitializerList { + switch p.rune() { + case ',': + t := p.tok + prev.Initializer.trailingComma = &t + if p.peek(false) == '}' { + return r + } + + t = p.shift() + d = nil + switch p.rune() { + case '[', '.': + d = p.designation() + case IDENTIFIER: + if p.peek(false) == ':' { + d = p.designation() + } + } + prev.InitializerList = &InitializerList{Token: t, Designation: d, Initializer: p.initializer(parent)} + default: + return r + } + } +} + +// designation: +// designator-list = +func (p *parser) designation() *Designation { + var t Token + list, colon := p.designatorList() + if !colon { + switch p.rune() { + case '=': + t = p.shift() + default: + p.err("expected =") + } + } + return &Designation{DesignatorList: list, Token: t} +} + +// designator-list: +// designator +// designator-list designator +func (p *parser) designatorList() (r *DesignatorList, colon bool) { + d, isCol := p.designator(true) + if isCol { + return &DesignatorList{Designator: d}, true + } + + r = &DesignatorList{Designator: d} + for prev := r; ; prev = prev.DesignatorList { + switch p.rune() { + case '[', '.': + d, _ = p.designator(false) + prev.DesignatorList = &DesignatorList{Designator: d} + default: + return r, false + } + } +} + +// designator: +// [ constant-expression ] +// . identifier +// identifier : +func (p *parser) designator(acceptCol bool) (*Designator, bool) { + var t, t2 Token + switch p.rune() { + case '[': + t = p.shift() + e := p.constantExpression() + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + return &Designator{Case: DesignatorIndex, Token: t, ConstantExpression: e, Token2: t2, lexicalScope: p.declScope}, false + case '.': + t = p.shift() + switch p.rune() { + case IDENTIFIER: + t2 = p.shift() + default: + p.err("expected identifier") + } + return &Designator{Case: DesignatorField, Token: t, Token2: t2, lexicalScope: p.declScope}, false + case IDENTIFIER: + if acceptCol && p.peek(false) == ':' { + t = p.shift() + return &Designator{Case: DesignatorField2, Token: t, Token2: p.shift(), lexicalScope: p.declScope}, true + } + + p.err("expected designator") + return nil, false + default: + p.err("expected [ or .") + return nil, false + } +} + +// [0], 6.8 Statements and blocks +// +// statement: +// labeled-statement +// compound-statement +// expression-statement +// selection-statement +// iteration-statement +// jump-statement +// asm-statement +func (p *parser) statement() *Statement { + switch p.rune() { + case IDENTIFIER: + if p.peek(false) == ':' { + return &Statement{Case: StatementLabeled, LabeledStatement: p.labeledStatement()} + } + + return &Statement{Case: StatementExpr, ExpressionStatement: p.expressionStatement()} + case '{': + return &Statement{Case: StatementCompound, CompoundStatement: p.compoundStatement(nil, nil)} + case IF, SWITCH: + return &Statement{Case: StatementSelection, SelectionStatement: p.selectionStatement()} + case WHILE, DO, FOR: + return &Statement{Case: StatementIteration, IterationStatement: p.iterationStatement()} + case GOTO, BREAK, CONTINUE, RETURN: + return &Statement{Case: StatementJump, JumpStatement: p.jumpStatement()} + case CASE, DEFAULT: + return &Statement{Case: StatementLabeled, LabeledStatement: p.labeledStatement()} + case ASM: + return &Statement{Case: StatementAsm, AsmStatement: p.asmStatement()} + default: + return &Statement{Case: StatementExpr, ExpressionStatement: p.expressionStatement()} + } +} + +// [0], 6.8.1 Labeled statements +// +// labeled-statement: +// identifier : statement +// case constant-expression : statement +// case constant-expression ... constant-expression : statement +// default : statement +func (p *parser) labeledStatement() (r *LabeledStatement) { + defer func() { + if r != nil { + p.block.labeledStmts = append(p.block.labeledStmts, r) + } + }() + + var t, t2, t3 Token + switch p.rune() { + case IDENTIFIER: + t = p.shift() + switch p.rune() { + case ':': + t2 = p.shift() + default: + p.err("expected :") + return nil + } + + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + p.block.hasLabel() + r = &LabeledStatement{ + Case: LabeledStatementLabel, Token: t, Token2: t2, AttributeSpecifierList: attr, + Statement: p.statement(), lexicalScope: p.declScope, block: p.block, + } + p.declScope.declare(t.Value, r) + return r + case CASE: + if p.switches == 0 { + p.err("case label not within a switch statement") + } + t = p.shift() + e := p.constantExpression() + switch p.rune() { + case DDD: + if p.ctx.cfg.RejectCaseRange { + p.err0(false, "expected :") + } + t2 = p.shift() + e2 := p.constantExpression() + switch p.rune() { + case ':': + t3 = p.shift() + default: + p.err("expected :") + } + return &LabeledStatement{ + Case: LabeledStatementRange, Token: t, ConstantExpression: e, + Token2: t2, ConstantExpression2: e2, Token3: t3, + Statement: p.statement(), lexicalScope: p.declScope, + block: p.block, + } + case ':': + t2 = p.shift() + default: + p.err("expected :") + } + return &LabeledStatement{ + Case: LabeledStatementCaseLabel, Token: t, ConstantExpression: e, + Token2: t2, Statement: p.statement(), lexicalScope: p.declScope, + block: p.block, + } + case DEFAULT: + if p.switches == 0 { + p.err("'deafult' label not within a switch statement") + } + t = p.shift() + switch p.rune() { + case ':': + t2 = p.shift() + default: + p.err("expected :") + } + return &LabeledStatement{ + Case: LabeledStatementDefault, Token: t, Token2: t2, Statement: p.statement(), + lexicalScope: p.declScope, block: p.block, + } + default: + p.err("expected labeled-statement") + return nil + } +} + +// [0], 6.8.2 Compound statement +// +// compound-statement: +// { block-item-list_opt } +func (p *parser) compoundStatement(s Scope, inject []Token) (r *CompoundStatement) { + if p.rune() != '{' { + p.err("expected {") + return nil + } + + r = &CompoundStatement{parent: p.block} + if fn := p.currFn; fn != nil { + fn.compoundStatements = append(fn.compoundStatements, r) + } + sv := p.block + if sv != nil { + sv.children = append(sv.children, r) + } + p.block = r + switch { + case s != nil: + p.declScope = s + p.resolveScope = s + p.scopes++ + // var a []string + // for s := p.declScope; s != nil; s = s.Parent() { + // a = append(a, fmt.Sprintf("%p", s)) + // } + // dbg("using func scope %p: %v", s, strings.Join(a, " ")) + default: + p.openScope(false) + } + s = p.declScope + p.typedefNameEnabled = true + t := p.shift() + if len(inject) != 0 { + p.unget(inject...) + } + list := p.blockItemList() + var t2 Token + p.closeScope() + p.typedefNameEnabled = true + switch p.rune() { + case '}': + t2 = p.shift() + default: + p.err("expected }") + } + r.Token = t + r.BlockItemList = list + r.Token2 = t2 + r.scope = s + p.block = sv + return r +} + +// block-item-list: +// block-item +// block-item-list block-item +func (p *parser) blockItemList() (r *BlockItemList) { + var prev *BlockItemList + for p.rune() != '}' && p.rune() > 0 { + n := &BlockItemList{BlockItem: p.blockItem()} + if r == nil { + r = n + prev = r + continue + } + + prev.BlockItemList = n + prev = n + } + return r +} + +// block-item: +// declaration +// statement +// label-declaration +// declaration-specifiers declarator compound-statement +func (p *parser) blockItem() *BlockItem { + switch p.rune() { + case + TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, + VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + CONST, RESTRICT, VOLATILE, + ALIGNAS, + INLINE, NORETURN, ATTRIBUTE: + ds := p.declarationSpecifiers(nil, nil) + switch p.rune() { + case ';': + r := &BlockItem{Case: BlockItemDecl, Declaration: p.declaration(ds, nil)} + p.typedefNameEnabled = true + return r + } + + d := p.declarator(true, ds.typedef(), nil) + switch p.rune() { + case '{': + if p.ctx.cfg.RejectNestedFunctionDefinitions { + p.err0(false, "nested functions not allowed") + } + r := &BlockItem{Case: BlockItemFuncDef, DeclarationSpecifiers: ds, Declarator: d, CompoundStatement: p.compoundStatement(d.ParamScope(), p.fn(d.Name()))} + p.typedefNameEnabled = true + return r + default: + r := &BlockItem{Case: BlockItemDecl, Declaration: p.declaration(ds, d)} + return r + } + case LABEL: + p.block.hasLabel() + return &BlockItem{Case: BlockItemLabel, LabelDeclaration: p.labelDeclaration()} + case PRAGMASTDC: + return &BlockItem{Case: BlockItemPragma, PragmaSTDC: p.pragmaSTDC()} + default: + return &BlockItem{Case: BlockItemStmt, Statement: p.statement()} + } +} + +// label-declaration +// __label__ identifier-list ; +func (p *parser) labelDeclaration() *LabelDeclaration { + if p.rune() != LABEL { + p.err("expected __label__") + return nil + } + + t := p.shift() + list := p.identifierList() + p.typedefNameEnabled = true + var t2 Token + switch p.rune() { + case ';': + t2 = p.shift() + default: + p.err("expected ;") + } + return &LabelDeclaration{Token: t, IdentifierList: list, Token2: t2} +} + +// [0], 6.8.3 Expression and null statements +// +// expression-statement: +// expression_opt attribute-specifier-list_opt; +func (p *parser) expressionStatement() *ExpressionStatement { + switch p.rune() { + case '}': + p.typedefNameEnabled = true + return &ExpressionStatement{} + case ';': + p.typedefNameEnabled = true + return &ExpressionStatement{Token: p.shift()} + case ATTRIBUTE: + p.typedefNameEnabled = true + attr := p.attributeSpecifierList() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + var t Token + switch p.rune() { + case ';': + t = p.shift() + default: + p.err("expected ;") + } + return &ExpressionStatement{AttributeSpecifierList: attr, Token: t} + } + + e := p.expression() + var t Token + p.typedefNameEnabled = true + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + switch p.rune() { + case ';': + t = p.shift() + default: + p.err("expected ;") + } + return &ExpressionStatement{Expression: e, AttributeSpecifierList: attr, Token: t} +} + +// [0], 6.8.4 Selection statements +// +// selection-statement: +// if ( expression ) statement +// if ( expression ) statement else statement +// switch ( expression ) statement +func (p *parser) selectionStatement() *SelectionStatement { + var t, t2, t3, t4 Token + switch p.rune() { + case IF: + p.openScope(false) + t = p.shift() + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + e := p.expression() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + p.openScope(false) + s := p.statement() + if p.peek(false) != ELSE { + r := &SelectionStatement{Case: SelectionStatementIf, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: s} + p.closeScope() + p.closeScope() + return r + } + + p.closeScope() + p.openScope(false) + t4 = p.shift() + r := &SelectionStatement{Case: SelectionStatementIfElse, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: s, Token4: t4, Statement2: p.statement()} + p.closeScope() + p.closeScope() + return r + case SWITCH: + p.switches++ + p.openScope(false) + t = p.shift() + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + e := p.expression() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + p.openScope(false) + s := p.statement() + p.closeScope() + p.closeScope() + p.switches-- + return &SelectionStatement{Case: SelectionStatementSwitch, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: s} + default: + p.err("expected selection-statement") + return nil + } +} + +// [0], 6.8.5 Iteration statements +// +// iteration-statement: +// while ( expression ) statement +// do statement while ( expression ) ; +// for ( expression_opt ; expression_opt ; expression_opt ) statement +// for ( declaration expression_opt ; expression_opt ) statement +func (p *parser) iterationStatement() (r *IterationStatement) { + var t, t2, t3, t4, t5 Token + var e, e2, e3 *Expression + switch p.rune() { + case WHILE: + p.openScope(false) + t = p.shift() + if p.rune() != '(' { + p.err("expected (") + p.closeScope() + return nil + } + + t2 = p.shift() + e = p.expression() + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + p.openScope(false) + r = &IterationStatement{Case: IterationStatementWhile, Token: t, Token2: t2, Expression: e, Token3: t3, Statement: p.statement()} + p.closeScope() + p.closeScope() + return r + case DO: + t := p.shift() + p.openScope(false) + p.openScope(false) + s := p.statement() + p.closeScope() + switch p.rune() { + case WHILE: + t2 = p.shift() + default: + p.err("expected while") + p.closeScope() + return nil + } + + if p.rune() != '(' { + p.err("expected (") + p.closeScope() + return nil + } + + t3 = p.shift() + e = p.expression() + switch p.rune() { + case ')': + t4 = p.shift() + default: + p.err("expected )") + } + p.typedefNameEnabled = true + switch p.rune() { + case ';': + t5 = p.shift() + default: + p.err("expected ;") + } + r = &IterationStatement{Case: IterationStatementDo, Token: t, Statement: s, Token2: t2, Token3: t3, Expression: e, Token4: t4, Token5: t5} + p.closeScope() + return r + case FOR: + p.openScope(false) + t = p.shift() + if p.rune() != '(' { + p.err("expected (") + p.closeScope() + return nil + } + + t2 = p.shift() + var d *Declaration + switch p.rune() { + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, + VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + CONST, RESTRICT, VOLATILE, + ALIGNAS, + INLINE, NORETURN, ATTRIBUTE: + d = p.declaration(nil, nil) + if p.rune() != ';' { + e = p.expression() + } + switch p.rune() { + case ';': + t3 = p.shift() + default: + p.err("expected ;") + } + if p.rune() != ')' { + e2 = p.expression() + } + switch p.rune() { + case ')': + t4 = p.shift() + default: + p.err("expected )") + } + p.openScope(false) + r = &IterationStatement{Case: IterationStatementForDecl, Token: t, Token2: t2, Declaration: d, Expression: e, Token3: t3, Expression2: e2, Token4: t4, Statement: p.statement()} + p.closeScope() + p.closeScope() + return r + default: + if p.rune() != ';' { + e = p.expression() + } + switch p.rune() { + case ';': + t3 = p.shift() + default: + p.err("expected ;") + } + if p.rune() != ';' { + e2 = p.expression() + } + switch p.rune() { + case ';': + t4 = p.shift() + default: + p.err("expected ;") + } + if p.rune() != ')' { + e3 = p.expression() + } + switch p.rune() { + case ')': + t5 = p.shift() + default: + p.err("expected )") + } + p.openScope(false) + r = &IterationStatement{Case: IterationStatementFor, Token: t, Token2: t2, Expression: e, Token3: t3, Expression2: e2, Token4: t4, Expression3: e3, Token5: t5, Statement: p.statement()} + p.closeScope() + p.closeScope() + return r + } + default: + p.err("expected iteration-statement") + return nil + } +} + +// [0], 6.8.6 Jump statements +// +// jump-statement: +// goto identifier ; +// goto * expression ; +// continue ; +// break ; +// return expression_opt ; +func (p *parser) jumpStatement() *JumpStatement { + var t, t2, t3 Token + var kind JumpStatementCase + switch p.rune() { + case GOTO: + p.typedefNameEnabled = false + t = p.shift() + switch p.rune() { + case IDENTIFIER: + t2 = p.shift() + case '*': + t2 = p.shift() + p.typedefNameEnabled = true + e := p.expression() + switch p.rune() { + case ';': + t3 = p.shift() + default: + p.err("expected ;") + } + return &JumpStatement{Case: JumpStatementGotoExpr, Token: t, Token2: t2, Expression: e, Token3: t3, lexicalScope: p.declScope} + default: + p.err("expected identifier or *") + } + p.typedefNameEnabled = true + switch p.rune() { + case ';': + t3 = p.shift() + default: + p.err("expected ;") + } + return &JumpStatement{Case: JumpStatementGoto, Token: t, Token2: t2, Token3: t3, lexicalScope: p.declScope} + case CONTINUE: + kind = JumpStatementContinue + case BREAK: + kind = JumpStatementBreak + case RETURN: + t = p.shift() + var e *Expression + if p.rune() != ';' { + e = p.expression() + } + p.typedefNameEnabled = true + switch p.rune() { + case ';': + t2 = p.shift() + default: + p.err("expected ;") + } + return &JumpStatement{Case: JumpStatementReturn, Token: t, Expression: e, Token2: t2, lexicalScope: p.declScope} + default: + p.err("expected jump-statement") + return nil + } + + t = p.shift() + p.typedefNameEnabled = true + switch p.rune() { + case ';': + t2 = p.shift() + default: + p.err("expected ;") + } + return &JumpStatement{Case: kind, Token: t, Token2: t2, lexicalScope: p.declScope} +} + +// [0], 6.9 External definitions +// +// translation-unit: +// external-declaration +// translation-unit external-declaration +func (p *parser) translationUnit() (r *TranslationUnit) { + p.typedefNameEnabled = true + var prev *TranslationUnit + for p.rune() >= 0 { + ed := p.externalDeclaration() + if ed == nil { + continue + } + + t := &TranslationUnit{ExternalDeclaration: ed} + switch { + case r == nil: + r = t + default: + prev.TranslationUnit = t + } + prev = t + } + if r != nil { + return r + } + + return &TranslationUnit{} +} + +// external-declaration: +// function-definition +// declaration +// asm-function-definition +// ; +func (p *parser) externalDeclaration() *ExternalDeclaration { + var ds *DeclarationSpecifiers + var inline, extern bool + if p.ctx.cfg.SharedFunctionDefinitions != nil { + p.rune() + p.hash.Reset() + p.key = sharedFunctionDefinitionKey{pos: dict.sid(p.tok.Position().String())} + p.hashTok() + } + switch p.rune() { + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, + VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + CONST, RESTRICT, VOLATILE, + INLINE, NORETURN, ATTRIBUTE, + ALIGNAS: + ds = p.declarationSpecifiers(&extern, &inline) + case ';': + if p.ctx.cfg.RejectEmptyDeclarations { + p.err("expected external-declaration") + return nil + } + + return &ExternalDeclaration{Case: ExternalDeclarationEmpty, Token: p.shift()} + case ASM: + return &ExternalDeclaration{Case: ExternalDeclarationAsmStmt, AsmStatement: p.asmStatement()} + case PRAGMASTDC: + return &ExternalDeclaration{Case: ExternalDeclarationPragma, PragmaSTDC: p.pragmaSTDC()} + default: + if p.ctx.cfg.RejectMissingDeclarationSpecifiers { + p.err("expected declaration-specifiers") + } + } + if p.rune() == ';' { + return &ExternalDeclaration{Case: ExternalDeclarationDecl, Declaration: p.declaration(ds, nil)} + } + + p.rune() + d := p.declarator(false, ds.typedef(), nil) + p.declScope.declare(d.Name(), d) + switch p.rune() { + case ',', ';', '=', ATTRIBUTE: + if ds == nil { + ds = noDeclSpecs + } + r := &ExternalDeclaration{Case: ExternalDeclarationDecl, Declaration: p.declaration(ds, d)} + return r + case ASM: + return &ExternalDeclaration{Case: ExternalDeclarationAsm, AsmFunctionDefinition: p.asmFunctionDefinition(ds, d)} + default: + fd := p.functionDefinition(ds, d) + if sfd := p.ctx.cfg.SharedFunctionDefinitions; sfd != nil { + p.key.nm = d.Name() + p.key.hash = p.hash.Sum64() + if ex := sfd.m[p.key]; ex != nil { + sfd.M[ex] = struct{}{} + d := ex.Declarator + p.declScope.declare(d.Name(), d) + r := &ExternalDeclaration{Case: ExternalDeclarationFuncDef, FunctionDefinition: ex} + return r + } + + sfd.m[p.key] = fd + } + + r := &ExternalDeclaration{Case: ExternalDeclarationFuncDef, FunctionDefinition: fd} + return r + } +} + +func (p *parser) pragmaSTDC() *PragmaSTDC { + if p.rune() != PRAGMASTDC { + p.err("expected __pragma_stdc") + } + + t := p.shift() // _Pragma + t2 := p.shift() // STDC + t3 := p.shift() // FOO + t4 := p.shift() // Bar + return &PragmaSTDC{Token: t, Token2: t2, Token3: t3, Token4: t4} +} + +// [0], 6.9.1 Function definitions +// +// function-definition: +// declaration-specifiers declarator declaration-list_opt compound-statement +func (p *parser) functionDefinition(ds *DeclarationSpecifiers, d *Declarator) (r *FunctionDefinition) { + var list *DeclarationList + s := d.ParamScope() + switch { + case p.rune() != '{': // As in: int f(i) int i; { return i; } + list = p.declarationList(s) + case d.DirectDeclarator != nil && d.DirectDeclarator.Case == DirectDeclaratorFuncIdent: // As in: int f(i) { return i; } + d.DirectDeclarator.idListNoDeclList = true + for n := d.DirectDeclarator.IdentifierList; n != nil; n = n.IdentifierList { + tok := n.Token2 + if tok.Value == 0 { + tok = n.Token + } + d := &Declarator{ + IsParameter: true, + DirectDeclarator: &DirectDeclarator{ + Case: DirectDeclaratorIdent, + Token: tok, + }, + } + s.declare(tok.Value, d) + if p.ctx.cfg.RejectMissingDeclarationSpecifiers { + p.ctx.errNode(&tok, "expected declaration-specifiers") + } + } + } + p.block = nil + r = &FunctionDefinition{DeclarationSpecifiers: ds, Declarator: d, DeclarationList: list} + sv := p.currFn + p.currFn = r + r.CompoundStatement = p.compoundStatement(d.ParamScope(), p.fn(d.Name())) + p.currFn = sv + return r +} + +func (p *parser) fn(nm StringID) (r []Token) { + if p.ctx.cfg.PreprocessOnly { + return nil + } + + pos := p.tok.Position() + toks := []Token{ + {Rune: STATIC, Value: idStatic, Src: idStatic}, + {Rune: CONST, Value: idConst, Src: idConst}, + {Rune: CHAR, Value: idChar, Src: idChar}, + {Rune: IDENTIFIER, Value: idFunc, Src: idFunc}, + {Rune: '[', Value: idLBracket, Src: idLBracket}, + {Rune: ']', Value: idRBracket, Src: idRBracket}, + {Rune: '=', Value: idEq, Src: idEq}, + {Rune: STRINGLITERAL, Value: nm, Src: nm}, + {Rune: ';', Value: idSemicolon, Src: idSemicolon}, + } + if p.ctx.cfg.InjectTracingCode { + id := dict.sid(fmt.Sprintf("%s:%s\n", pos, nm.String())) + toks = append(toks, []Token{ + {Rune: IDENTIFIER, Value: idFprintf, Src: idFprintf}, + {Rune: '(', Value: idLParen, Src: idLParen}, + {Rune: IDENTIFIER, Value: idStderr, Src: idStderr}, + {Rune: ',', Value: idComma, Src: idComma}, + {Rune: STRINGLITERAL, Value: id, Src: id}, + {Rune: ')', Value: idRParen, Src: idRParen}, + {Rune: ';', Value: idSemicolon, Src: idSemicolon}, + {Rune: IDENTIFIER, Value: idFFlush, Src: idFFlush}, + {Rune: '(', Value: idLParen, Src: idLParen}, + {Rune: IDENTIFIER, Value: idStderr, Src: idStderr}, + {Rune: ')', Value: idRParen, Src: idRParen}, + {Rune: ';', Value: idSemicolon, Src: idSemicolon}, + }...) + } + for _, v := range toks { + v.file = p.tok.file + v.pos = p.tok.pos + v.seq = p.tok.seq + r = append(r, v) + } + return r +} + +// declaration-list: +// declaration +// declaration-list declaration +func (p *parser) declarationList(s Scope) (r *DeclarationList) { + p.declScope = s + p.resolveScope = s + switch ch := p.rune(); ch { + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, + VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + CONST, RESTRICT, VOLATILE, + ALIGNAS, + INLINE, NORETURN, ATTRIBUTE: + r = &DeclarationList{Declaration: p.declaration(nil, nil)} + default: + p.err("expected declaration: %s", tokName(ch)) + return nil + } + + for prev := r; ; prev = prev.DeclarationList { + switch p.rune() { + case TYPEDEF, EXTERN, STATIC, AUTO, REGISTER, THREADLOCAL, + VOID, CHAR, SHORT, INT, INT8, INT16, INT32, INT64, INT128, LONG, FLOAT, FLOAT16, FLOAT80, FLOAT32, FLOAT32X, FLOAT64, FLOAT64X, FLOAT128, DECIMAL32, DECIMAL64, DECIMAL128, FRACT, SAT, ACCUM, DOUBLE, SIGNED, UNSIGNED, BOOL, COMPLEX, STRUCT, UNION, ENUM, TYPEDEFNAME, TYPEOF, ATOMIC, + CONST, RESTRICT, VOLATILE, + ALIGNAS, + INLINE, NORETURN, ATTRIBUTE: + prev.DeclarationList = &DeclarationList{Declaration: p.declaration(nil, nil)} + default: + return r + } + } +} + +// ----------------------------------------------------------------- Extensions + +// asm-function-definition: +// declaration-specifiers declarator asm-statement +func (p *parser) asmFunctionDefinition(ds *DeclarationSpecifiers, d *Declarator) *AsmFunctionDefinition { + return &AsmFunctionDefinition{DeclarationSpecifiers: ds, Declarator: d, AsmStatement: p.asmStatement()} +} + +// asm-statement: +// asm attribute-specifier-list_opt ; +func (p *parser) asmStatement() *AsmStatement { + a := p.asm() + attr := p.attributeSpecifierListOpt() + // if attr != nil { + // trc("%v: ATTRS", attr.Position()) + // } + var t Token + switch p.rune() { + case ';': + p.typedefNameEnabled = true + t = p.shift() + default: + p.err("expected ';'") + } + + return &AsmStatement{Asm: a, AttributeSpecifierList: attr, Token: t} +} + +// asm: +// asm asm-qualifier-list_opt ( string-literal asm-arg-list_opt ) +func (p *parser) asm() *Asm { + var t, t2, t3, t4 Token + switch p.rune() { + case ASM: + t = p.shift() + default: + p.err("expected asm") + } + + var qlist *AsmQualifierList + switch p.rune() { + case VOLATILE, INLINE, GOTO: + qlist = p.asmQualifierList() + } + + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + + switch p.rune() { + case STRINGLITERAL: + t3 = p.shift() + default: + p.err("expected string-literal") + } + + var argList *AsmArgList + switch p.rune() { + case ':': + argList = p.asmArgList() + } + + switch p.rune() { + case ')': + t4 = p.shift() + default: + p.err("expected )") + } + + return &Asm{Token: t, AsmQualifierList: qlist, Token2: t2, Token3: t3, AsmArgList: argList, Token4: t4} +} + +// asm-qualifier-list: +// asm-qualifier +// asm-qualifier-list asm-qualifier +func (p *parser) asmQualifierList() (r *AsmQualifierList) { + switch p.rune() { + case VOLATILE, INLINE, GOTO: + r = &AsmQualifierList{AsmQualifier: p.asmQualifier()} + default: + p.err("expected asm-qualifier-list") + return nil + } + + for prev := r; ; prev = prev.AsmQualifierList { + switch p.rune() { + case VOLATILE, INLINE, GOTO: + prev.AsmQualifierList = &AsmQualifierList{AsmQualifier: p.asmQualifier()} + default: + return r + } + } +} + +// asm-qualifier: +// volatile +// inline +// goto" +func (p *parser) asmQualifier() *AsmQualifier { + switch p.rune() { + case VOLATILE: + return &AsmQualifier{Case: AsmQualifierVolatile, Token: p.shift()} + case INLINE: + return &AsmQualifier{Case: AsmQualifierInline, Token: p.shift()} + case GOTO: + return &AsmQualifier{Case: AsmQualifierGoto, Token: p.shift()} + default: + p.err("expected asm-qualifier") + return nil + } +} + +// asm-arg-list: +// : ExpressionListOpt +// asm-arg-list : expression-list_opt +func (p *parser) asmArgList() (r *AsmArgList) { + if p.rune() != ':' { + p.err("expected :") + return nil + } + + t := p.shift() + var list *AsmExpressionList + switch p.rune() { + case ':', ')': + default: + list = p.asmExpressionList() + } + r = &AsmArgList{Token: t, AsmExpressionList: list} + for prev := r; p.rune() == ':'; prev = prev.AsmArgList { + t := p.shift() + switch p.rune() { + case ':', ')': + default: + list = p.asmExpressionList() + } + prev.AsmArgList = &AsmArgList{Token: t, AsmExpressionList: list} + } + return r +} + +// asm-expression-list: +// asm-index_opt assignment-expression +// asm-expression-list , asm-index_opt assignment-expression +func (p *parser) asmExpressionList() (r *AsmExpressionList) { + var x *AsmIndex + if p.rune() == '[' { + x = p.asmIndex() + } + + r = &AsmExpressionList{AsmIndex: x, AssignmentExpression: p.assignmentExpression()} + for prev := r; p.rune() == ','; prev = prev.AsmExpressionList { + t := p.shift() + if p.rune() == '[' { + x = p.asmIndex() + } + prev.AsmExpressionList = &AsmExpressionList{Token: t, AsmIndex: x, AssignmentExpression: p.assignmentExpression()} + } + return r +} + +// asm-index: +// [ expression ] +func (p *parser) asmIndex() *AsmIndex { + if p.rune() != '[' { + p.err("expected [") + return nil + } + + t := p.shift() + e := p.expression() + var t2 Token + switch p.rune() { + case ']': + t2 = p.shift() + default: + p.err("expected ]") + } + return &AsmIndex{Token: t, Expression: e, Token2: t2} +} + +// attribute-specifier-list: +// attribute-specifier +// attribute-specifier-list attribute-specifier +func (p *parser) attributeSpecifierList() (r *AttributeSpecifierList) { + if p.rune() != ATTRIBUTE { + p.err("expected __attribute__") + return nil + } + + r = &AttributeSpecifierList{AttributeSpecifier: p.attributeSpecifier()} + for prev := r; p.rune() == ATTRIBUTE; prev = r.AttributeSpecifierList { + prev.AttributeSpecifierList = &AttributeSpecifierList{AttributeSpecifier: p.attributeSpecifier()} + } + return r +} + +// attribute-specifier: +// __attribute__ (( attribute-value-list_opt )) +func (p *parser) attributeSpecifier() (r *AttributeSpecifier) { + if p.rune() != ATTRIBUTE { + p.err("expected __attribute__") + return nil + } + + en := p.typedefNameEnabled + t := p.shift() + var t2, t3, t4, t5 Token + p.ignoreKeywords = true + switch p.rune() { + case '(': + t2 = p.shift() + default: + p.err("expected (") + } + switch p.rune() { + case '(': + t3 = p.shift() + default: + p.err("expected (") + } + var list *AttributeValueList + if p.rune() != ')' { + list = p.attributeValueList() + } + p.ignoreKeywords = false + p.typedefNameEnabled = en + switch p.rune() { + case ')': + t4 = p.shift() + default: + p.err("expected )") + } + switch p.rune() { + case ')': + t5 = p.shift() + default: + p.err("expected )") + } + return &AttributeSpecifier{Token: t, Token2: t2, Token3: t3, AttributeValueList: list, Token4: t4, Token5: t5} +} + +// attribute-value-list: +// attribute-value +// attribute-value-list , attribute-value +func (p *parser) attributeValueList() (r *AttributeValueList) { + r = &AttributeValueList{AttributeValue: p.attributeValue()} + for prev := r; p.rune() == ','; prev = prev.AttributeValueList { + t := p.shift() + prev.AttributeValueList = &AttributeValueList{Token: t, AttributeValue: p.attributeValue()} + } + return r +} + +// attribute-value: +// identifier +// identifier ( expression-list_opt ) +func (p *parser) attributeValue() *AttributeValue { + if p.rune() != IDENTIFIER { + p.err("expected identifier") + return nil + } + + t := p.shift() + if p.rune() != '(' { + return &AttributeValue{Case: AttributeValueIdent, Token: t, lexicalScope: p.declScope} + } + + p.ignoreKeywords = false + t2 := p.shift() + var list *ExpressionList + if p.rune() != ')' { + list = p.expressionList() + } + p.ignoreKeywords = true + var t3 Token + switch p.rune() { + case ')': + t3 = p.shift() + default: + p.err("expected )") + } + return &AttributeValue{Case: AttributeValueExpr, Token: t, Token2: t2, ExpressionList: list, Token3: t3, lexicalScope: p.declScope} +} + +// expression-list: +// assignment-expression +// expression-list , assignment-expression +func (p *parser) expressionList() (r *ExpressionList) { + r = &ExpressionList{AssignmentExpression: p.assignmentExpression()} + for prev := r; p.rune() == ','; prev = prev.ExpressionList { + t := p.shift() + prev.ExpressionList = &ExpressionList{Token: t, AssignmentExpression: p.assignmentExpression()} + } + return r +} diff --git a/vendor/modernc.org/cc/v3/parser.yy b/vendor/modernc.org/cc/v3/parser.yy new file mode 100644 index 00000000..a51b600b --- /dev/null +++ b/vendor/modernc.org/cc/v3/parser.yy @@ -0,0 +1,1033 @@ +%{ +// 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. + +// Based on [0], 6.5-6.10. + +package cc // import "modernc.org/cc/v3" + +%} + +%union { + Token Token + node Node +} + +%token + /*yy:token "%c" */ IDENTIFIER + /*yy:token "%c_e" */ ENUMCONST + /*yy:token "%c_t" */ TYPEDEFNAME + /*yy:token "%d" */ INTCONST + /*yy:token "'%c'" */ CHARCONST + /*yy:token "1.%d" */ FLOATCONST + /*yy:token "L'%c'" */ LONGCHARCONST + /*yy:token "L\"%c\"" */ LONGSTRINGLITERAL + /*yy:token "\"%c\"" */ STRINGLITERAL + + ACCUM "_Accum" + ADDASSIGN "+=" + ALIGNAS "_Alignas" + ALIGNOF "_Alignof" + ANDAND "&&" + ANDASSIGN "&=" + ARROW "->" + ASM "__asm__" + ATOMIC "_Atomic" + ATTRIBUTE "__attribute__" + AUTO "auto" + BOOL "_Bool" + BREAK "break" + BUILTINCHOOSEXPR "__builtin_choose_expr" + BUILTINTYPESCOMPATIBLE "__builtin_types_compatible_p" + CASE "case" + CHAR "char" + COMPLEX "_Complex" + CONST "const" + CONTINUE "continue" + DDD "..." + DEC "--" + DECIMAL128 "_Decimal128" + DECIMAL32 "_Decimal32" + DECIMAL64 "_Decimal64" + DEFAULT "default" + DIVASSIGN "/=" + DO "do" + DOUBLE "double" + ELSE "else" + ENUM "enum" + EQ "==" + EXTERN "extern" + FLOAT "float" + FLOAT128 "_Float128" + FLOAT16 "__fp16" + FLOAT32 "_Float32" + FLOAT32X "_Float32x" + FLOAT64 "_Float64" + FLOAT64x "_Float64x" + FLOAT80 "__float80" + FOR "for" + FRACT "_Fract" + GEQ ">=" + GOTO "goto" + IF "if" + IMAG "__imag__" + INC "++" + INLINE "inline" + INT "int" + INT8 "__int8" + INT16 "__int16" + INT32 "__int32" + INT64 "__int64" + INT128 "__int128" + LABEL "__label__" + LEQ "<=" + LONG "long" + LSH "<<" + LSHASSIGN "<<=" + MODASSIGN "%=" + MULASSIGN "*=" + NEQ "!=" + NORETURN "_Noreturn" + ORASSIGN "|=" + OROR "||" + PPNUMBER "preprocessing number" + PPPASTE "##" + PRAGMASTDC "__pragma_stdc" + REAL "__real__" + REGISTER "register" + RESTRICT "restrict" + RETURN "return" + RSH ">>" + RSHASSIGN ">>=" + SAT "_Sat" + SHORT "short" + SIGNED "signed" + SIZEOF "sizeof" + STATIC "static" + STRUCT "struct" + SUBASSIGN "-=" + SWITCH "switch" + THREADLOCAL "_Thread_local" + TYPEDEF "typedef" + TYPEOF "typeof" + UNION "union" + UNSIGNED "unsigned" + VOID "void" + VOLATILE "volatile" + WHILE "while" + XORASSIGN "^=" + +%precedence BELOW_ELSE +%precedence ELSE + +%precedence BELOW_ATTRIBUTE +%precedence ATTRIBUTE + +%start TranslationUnit + +%% + + /* [0], 6.5.1 Primary expressions */ + /*yy:field Operand Operand */ + /*yy:field lexicalScope Scope */ + /*yy:field resolvedIn Scope */ + /*yy:field resolvedTo Node */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Ident */ + PrimaryExpression: + IDENTIFIER + /*yy:example int i = 42; */ +/*yy:case Int */ | INTCONST + /*yy:example int i = 3.14; */ +/*yy:case Float */ | FLOATCONST + /*yy:example enum e {a}; int i = a; */ +/*yy:case Enum */ | ENUMCONST + /*yy:example int i = 'x'; */ +/*yy:case Char */ | CHARCONST + /*yy:example int i = L'x'; */ +/*yy:case LChar */ | LONGCHARCONST + /*yy:example char *c = "x"; */ +/*yy:case String */ | STRINGLITERAL + /*yy:example char *c = L"x"; */ +/*yy:case LString */ | LONGSTRINGLITERAL + /*yy:example int i = (x+y); */ +/*yy:case Expr */ | '(' Expression ')' + /*yy:example int i = ({x();}); */ +/*yy:case Stmt */ | '(' CompoundStatement ')' + + /* [0], 6.5.2 Postfix operators */ + /*yy:field Operand Operand */ + /*yy:field Field Field // Case Select, PSelect */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Primary */ PostfixExpression: + PrimaryExpression + /*yy:example int i = x[y]; */ +/*yy:case Index */ | PostfixExpression '[' Expression ']' + /*yy:example int i = x(y); */ +/*yy:case Call */ | PostfixExpression '(' ArgumentExpressionList ')' + /*yy:example int i = x.y; */ +/*yy:case Select */ | PostfixExpression '.' IDENTIFIER + /*yy:example int i = x->y; */ +/*yy:case PSelect */ | PostfixExpression "->" IDENTIFIER + /*yy:example int i = x++; */ +/*yy:case Inc */ | PostfixExpression "++" + /*yy:example int i = x--; */ +/*yy:case Dec */ | PostfixExpression "--" + /*yy:example int i = (int[]){y}; */ +/*yy:case Complit */ | '(' TypeName ')' '{' InitializerList ',' '}' + /*yy:example int i = __builtin_types_compatible_p(int, double); */ +/*yy:case TypeCmp */ | "__builtin_types_compatible_p" '(' TypeName ',' TypeName ')' + /*yy:example int i = __builtin_choose_expr(1, 2, "foo"); */ +/*yy:case ChooseExpr*/ | "__builtin_choose_expr" '(' AssignmentExpression ',' AssignmentExpression ',' AssignmentExpression ')' + + /*yy:example int i = f(x); */ + ArgumentExpressionList: + AssignmentExpression + /*yy:example int i = f(x, y); */ + | ArgumentExpressionList ',' AssignmentExpression + + /* [0], 6.5.3 Unary operators */ + /*yy:field Operand Operand */ + /*yy:field lexicalScope Scope */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Postfix */ UnaryExpression: + PostfixExpression + /*yy:example int i = ++x; */ +/*yy:case Inc */ | "++" UnaryExpression + /*yy:example int i = --x; */ +/*yy:case Dec */ | "--" UnaryExpression + /*yy:example int *i = &x; */ +/*yy:case Addrof */ | '&' CastExpression + /*yy:example int i = *x; */ +/*yy:case Deref */ | '*' CastExpression + /*yy:example int i = +x; */ +/*yy:case Plus */ | '+' CastExpression + /*yy:example int i = -x; */ +/*yy:case Minus */ | '-' CastExpression + /*yy:example int i = ~x; */ +/*yy:case Cpl */ | '~' CastExpression + /*yy:example int i = !x; */ +/*yy:case Not */ | '!' CastExpression + /*yy:example int i = sizeof x; */ +/*yy:case SizeofExpr */ | "sizeof" UnaryExpression + /*yy:example int i = sizeof(int); */ +/*yy:case SizeofType */ | "sizeof" '(' TypeName ')' + /*yy:example int f() { L: &&L; }*/ +/*yy:case LabelAddr */ | "&&" IDENTIFIER + /*yy:example int i = _Alignof(x); */ +/*yy:case AlignofExpr*/ | "_Alignof" UnaryExpression + /*yy:example int i = _Alignof(int); */ +/*yy:case AlignofType*/ | "_Alignof" '(' TypeName ')' + /*yy:example double i = __imag__ x; */ +/*yy:case Imag */ | "__imag__" UnaryExpression + /*yy:example double i = __real__ x; */ +/*yy:case Real */ | "__real__" UnaryExpression + + /* [0], 6.5.4 Cast operators */ + /*yy:field Operand Operand */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = 42; */ +/*yy:case Unary */ CastExpression: + UnaryExpression + /*yy:example int i = (int)3.14; */ +/*yy:case Cast */ | '(' TypeName ')' CastExpression + + /* [0], 6.5.5 Multiplicative operators */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x;*/ +/*yy:case Cast */ MultiplicativeExpression: + CastExpression + /*yy:example int i = x * y;*/ +/*yy:case Mul */ | MultiplicativeExpression '*' CastExpression + /*yy:example int i = x / y;*/ +/*yy:case Div */ | MultiplicativeExpression '/' CastExpression + /*yy:example int i = x % y;*/ +/*yy:case Mod */ | MultiplicativeExpression '%' CastExpression + + /* [0], 6.5.6 Additive operators */ + /*yy:field lexicalScope Scope */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Mul */ AdditiveExpression: + MultiplicativeExpression + /*yy:example int i = x+y; */ +/*yy:case Add */ | AdditiveExpression '+' MultiplicativeExpression + /*yy:example int i = x-y; */ +/*yy:case Sub */ | AdditiveExpression '-' MultiplicativeExpression + + /* [0], 6.5.7 Bitwise shift operators */ + /*yy:field Operand Operand */ + /*yy:field promote Type // shift count promoted type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Add */ ShiftExpression: + AdditiveExpression + /*yy:example int i = x << y; */ +/*yy:case Lsh */ | ShiftExpression "<<" AdditiveExpression + /*yy:example int i = x >> y; */ +/*yy:case Rsh */ | ShiftExpression ">>" AdditiveExpression + + /* [0], 6.5.8 Relational operators */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Shift */ RelationalExpression: + ShiftExpression + /*yy:example int i = x < y; */ +/*yy:case Lt */ | RelationalExpression '<' ShiftExpression + /*yy:example int i = x > y; */ +/*yy:case Gt */ | RelationalExpression '>' ShiftExpression + /*yy:example int i = x <= y; */ +/*yy:case Leq */ | RelationalExpression "<=" ShiftExpression + /*yy:example int i = x >= y; */ +/*yy:case Geq */ | RelationalExpression ">=" ShiftExpression + + /* [0], 6.5.9 Equality operators */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Rel */ EqualityExpression: + RelationalExpression + /*yy:example int i = x == y; */ +/*yy:case Eq */ | EqualityExpression "==" RelationalExpression + /*yy:example int i = x != y; */ +/*yy:case Neq */ | EqualityExpression "!=" RelationalExpression + + /* [0], 6.5.10 Bitwise AND operator */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Eq */ AndExpression: + EqualityExpression + /*yy:example int i = x & y; */ +/*yy:case And */ | AndExpression '&' EqualityExpression + + /* [0], 6.5.11 Bitwise exclusive OR operator */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case And */ ExclusiveOrExpression: + AndExpression + /*yy:example int i = x^y; */ +/*yy:case Xor */ | ExclusiveOrExpression '^' AndExpression + + /* [0], 6.5.12 Bitwise inclusive OR operator */ + /*yy:field Operand Operand */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case Xor */ InclusiveOrExpression: + ExclusiveOrExpression + /*yy:example int i = x|y; */ +/*yy:case Or */ | InclusiveOrExpression '|' ExclusiveOrExpression + + /* [0], 6.5.13 Logical AND operator */ + /*yy:field Operand Operand */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x;*/ +/*yy:case Or */ LogicalAndExpression: + InclusiveOrExpression + /*yy:example int i = x && y;*/ +/*yy:case LAnd */ | LogicalAndExpression "&&" InclusiveOrExpression + + /* [0], 6.5.14 Logical OR operator */ + /*yy:field Operand Operand */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x;*/ +/*yy:case LAnd */ LogicalOrExpression: + LogicalAndExpression + /*yy:example int i = x || y;*/ +/*yy:case LOr */ | LogicalOrExpression "||" LogicalAndExpression + + /* [0], 6.5.15 Conditional operator */ + /*yy:field Operand Operand */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; */ +/*yy:case LOr */ ConditionalExpression: + LogicalOrExpression + /*yy:example int i = x ? y : z; */ +/*yy:case Cond */ | LogicalOrExpression '?' Expression ':' ConditionalExpression + + /* [0], 6.5.16 Assignment operators */ + /*yy:field Operand Operand */ + /*yy:field InitializerOperand Operand // When the expression is used in an initializer */ + /*yy:field lexicalScope Scope */ + /*yy:field promote Type */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int i = x; } */ +/*yy:case Cond */ AssignmentExpression: + ConditionalExpression + /*yy:example int f() { x = y; } */ +/*yy:case Assign */ | UnaryExpression '=' AssignmentExpression + /*yy:example int f() { x *= y; } */ +/*yy:case Mul */ | UnaryExpression "*=" AssignmentExpression + /*yy:example int f() { x /= y; } */ +/*yy:case Div */ | UnaryExpression "/=" AssignmentExpression + /*yy:example int f() { x %= y; } */ +/*yy:case Mod */ | UnaryExpression "%=" AssignmentExpression + /*yy:example int f() { x += y; } */ +/*yy:case Add */ | UnaryExpression "+=" AssignmentExpression + /*yy:example int f() { x -= y; } */ +/*yy:case Sub */ | UnaryExpression "-=" AssignmentExpression + /*yy:example int f() { x <<= y; } */ +/*yy:case Lsh */ | UnaryExpression "<<=" AssignmentExpression + /*yy:example int f() { x >>= y; } */ +/*yy:case Rsh */ | UnaryExpression ">>=" AssignmentExpression + /*yy:example int f() { x &= y; } */ +/*yy:case And */ | UnaryExpression "&=" AssignmentExpression + /*yy:example int f() { x ^= y; } */ +/*yy:case Xor */ | UnaryExpression "^=" AssignmentExpression + /*yy:example int f() { x |= y; } */ +/*yy:case Or */ | UnaryExpression "|=" AssignmentExpression + + /* [0], 6.5.17 Comma operator */ + /*yy:field Operand Operand */ + /*yy:field IsSideEffectsFree bool */ + /*yy:example int f() { i = x; }; */ +/*yy:case Assign */ Expression: + AssignmentExpression + /*yy:example int f() { x, y; }; */ +/*yy:case Comma */ | Expression ',' AssignmentExpression + + /* [0], 6.6 Constant expressions */ + /*yy:field Operand Operand */ + /*yy:example struct { int i:3; }; */ + ConstantExpression: + ConditionalExpression + + /* [0], 6.7 Declarations */ + /*yy:example int i, j; */ + Declaration: + DeclarationSpecifiers InitDeclaratorList ';' + + /*yy:field class storageClass */ + /*yy:example static int i; */ +/*yy:case Storage */ DeclarationSpecifiers: + StorageClassSpecifier DeclarationSpecifiers + /*yy:example int i; */ +/*yy:case TypeSpec */ | TypeSpecifier DeclarationSpecifiers + /*yy:example volatile int i; */ +/*yy:case TypeQual */ | TypeQualifier DeclarationSpecifiers + /*yy:example inline int f() {} */ +/*yy:case Func */ | FunctionSpecifier DeclarationSpecifiers + /*yy:example _Alignas(double) int i; */ +/*yy:case AlignSpec */ | AlignmentSpecifier DeclarationSpecifiers + /*yy:example int __attribute__((a)) i; */ +/*yy:case Attribute */ | AttributeSpecifier DeclarationSpecifiers + + /*yy:example int i; */ + InitDeclaratorList: + InitDeclarator + /*yy:example int i, j; */ + | InitDeclaratorList ',' AttributeSpecifierList InitDeclarator + + /*yy:field initializer *InitializerValue */ + /*yy:example int i; */ +/*yy:case Decl */ InitDeclarator: + Declarator AttributeSpecifierList + /*yy:example int i = x; */ +/*yy:case Init */ | Declarator AttributeSpecifierList '=' Initializer + + /* [0], 6.7.1 Storage-class specifiers */ + /*yy:example typedef int int_t;*/ +/*yy:case Typedef */ StorageClassSpecifier: + "typedef" + /*yy:example extern int i;*/ +/*yy:case Extern */ | "extern" + /*yy:example static int i;*/ +/*yy:case Static */ | "static" + /*yy:example auto int i;*/ +/*yy:case Auto */ | "auto" + /*yy:example register int i;*/ +/*yy:case Register */ | "register" + /*yy:example _Thread_local int i;*/ +/*yy:case ThreadLocal*/ | "_Thread_local" + + /* [0], 6.7.2 Type specifiers */ + /*yy:field resolvedIn Scope // Case TypedefName */ + /*yy:field typ Type */ + /*yy:example void i(); */ +/*yy:case Void */ TypeSpecifier: + "void" + /*yy:example char i; */ +/*yy:case Char */ | "char" + /*yy:example short i; */ +/*yy:case Short */ | "short" + /*yy:example int i; */ +/*yy:case Int */ | "int" + /*yy:example __int8 i; */ +/*yy:case Int8 */ | "__int8" + /*yy:example __int16 i; */ +/*yy:case Int16 */ | "__int16" + /*yy:example __int32 i; */ +/*yy:case Int32 */ | "__int32" + /*yy:example __int64 i; */ +/*yy:case Int64 */ | "__int64" + /*yy:example __int128 i; */ +/*yy:case Int128 */ | "__int128" + /*yy:example long i; */ +/*yy:case Long */ | "long" + /*yy:example float i; */ +/*yy:case Float */ | "float" + /*yy:example __fp16 i; */ +/*yy:case Float16 */ | "__fp16" + /*yy:example _Decimal32 i; */ +/*yy:case Decimal32 */ | "_Decimal32" + /*yy:example _Decimal64 i; */ +/*yy:case Decimal64 */ | "_Decimal64" + /*yy:example _Decimal128 i; */ +/*yy:case Decimal128 */ | "_Decimal128" + /*yy:example _Float128 i; */ +/*yy:case Float128 */ | "_Float128" + /*yy:example __float80 i; */ +/*yy:case Float80 */ | "__float80" + /*yy:example double i; */ +/*yy:case Double */ | "double" + /*yy:example signed i; */ +/*yy:case Signed */ | "signed" + /*yy:example unsigned i; */ +/*yy:case Unsigned */ | "unsigned" + /*yy:example _Bool i; */ +/*yy:case Bool */ | "_Bool" + /*yy:example _Complex i; */ +/*yy:case Complex */ | "_Complex" + /*yy:example struct s i; */ +/*yy:case StructOrUnion */ + | StructOrUnionSpecifier + /*yy:example enum e i; */ +/*yy:case Enum */ | EnumSpecifier + /*yy:example typedef const T; T i; */ +/*yy:case TypedefName*/ | TYPEDEFNAME + /*yy:example typeof(42) i; */ +/*yy:case TypeofExpr */ | "typeof" '(' Expression ')' + /*yy:example typedef const T; typeof(T) i; */ +/*yy:case TypeofType */ | "typeof" '(' TypeName ')' + /*yy:example _Atomic(int) i; */ +/*yy:case Atomic */ | AtomicTypeSpecifier + /*yy:example _Fract i; */ +/*yy:case Fract */ | "_Fract" + /*yy:example _Sat i; */ +/*yy:case Sat */ | "_Sat" + /*yy:example _Accum i; */ +/*yy:case Accum */ | "_Accum" + /*yy:example _Float32 i; */ +/*yy:case Float32 */ | "_Float32" + /*yy:example _Float64 i; */ +/*yy:case Float64 */ | "_Float64" + /*yy:example _Float32x i; */ +/*yy:case Float32x */ | "_Float32x" + /*yy:example _Float64x i; */ +/*yy:case Float64x */ | "_Float64x" + + /* [0], 6.7.2.1 Structure and union specifiers */ + /*yy:field lexicalScope Scope */ + /*yy:field maxAlign int */ + /*yy:field typ Type */ + /*yy:example struct s { int i; }; */ +/*yy:case Def */ StructOrUnionSpecifier: + StructOrUnion AttributeSpecifierList IDENTIFIER '{' StructDeclarationList '}' + /*yy:example struct s v; */ +/*yy:case Tag */ | StructOrUnion AttributeSpecifierList IDENTIFIER + + /*yy:example struct { int i; } s; */ +/*yy:case Struct */ StructOrUnion: + "struct" + /*yy:example union { int i; double d; } u; */ +/*yy:case Union */ | "union" + + /*yy:example struct{ int i; } */ + StructDeclarationList: + StructDeclaration + /*yy:example struct{ int i; double d; } */ + | StructDeclarationList StructDeclaration + + /*yy:example struct{ int i; } */ + /*yy:field Empty bool // TCC extension */ + StructDeclaration: + SpecifierQualifierList StructDeclaratorList ';' + + /*yy:field noStorageClass */ + /*yy:example struct {int i;};*/ +/*yy:case TypeSpec */ SpecifierQualifierList: + TypeSpecifier SpecifierQualifierList + /*yy:example struct {const int i;};*/ +/*yy:case TypeQual */ | TypeQualifier SpecifierQualifierList + /*yy:example struct {_Alignas(double) int i;};*/ +/*yy:case AlignSpec */ | AlignmentSpecifier SpecifierQualifierList + /*yy:example struct {__attribute__((a)) int i;};*/ +/*yy:case Attribute */ | AttributeSpecifier SpecifierQualifierList + + /*yy:example struct{ int i; } */ + StructDeclaratorList: + StructDeclarator + /*yy:example struct{ int i, j; } */ + | StructDeclaratorList ',' StructDeclarator + + /*yy:field decl *StructDeclaration */ + /*yy:example struct{ int i; } */ +/*yy:case Decl */ StructDeclarator: + Declarator + /*yy:example struct{ int i:3; } */ +/*yy:case BitField */ | Declarator ':' ConstantExpression AttributeSpecifierList + + /* [0], 6.7.2.2 Enumeration specifiers */ + /*yy:field lexicalScope Scope */ + /*yy:field typ Type */ + /*yy:field min Value */ + /*yy:field max Value */ + /*yy:example enum e {a}; */ +/*yy:case Def */ EnumSpecifier: + "enum" AttributeSpecifierList IDENTIFIER '{' EnumeratorList ',' '}' + /*yy:example enum e i; */ +/*yy:case Tag */ | "enum" AttributeSpecifierList IDENTIFIER + + /*yy:example enum e {a}; */ + EnumeratorList: + Enumerator + /*yy:example enum e {a, b}; */ + | EnumeratorList ',' Enumerator + + /*yy:field lexicalScope Scope */ + /*yy:field Operand Operand */ + /*yy:example enum e {a}; */ +/*yy:case Ident */ Enumerator: + IDENTIFIER AttributeSpecifierList + /*yy:example enum e {a = 42}; */ +/*yy:case Expr */ | IDENTIFIER AttributeSpecifierList '=' ConstantExpression + + /* [2], 6.7.2.4 Atomic type specifiers */ + /*yy:field list []*TypeSpecifier */ + /*yy:example _Atomic(int) i; */ + AtomicTypeSpecifier: + "_Atomic" '(' TypeName ')' + + /* [0], 6.7.3 Type qualifiers */ + /*yy:example const int i; */ +/*yy:case Const */ TypeQualifier: + "const" + /*yy:example restrict int i; */ +/*yy:case Restrict */ | "restrict" + /*yy:example volatile int i; */ +/*yy:case Volatile */ | "volatile" + /*yy:example _Atomic int i; */ +/*yy:case Atomic */ | "_Atomic" + + /* [0], 6.7.4 Function specifiers */ + /*yy:example inline int f() {}*/ +/*yy:case Inline */ FunctionSpecifier: + "inline" + /*yy:example _Noreturn int f() {}*/ +/*yy:case Noreturn */ | "_Noreturn" + + /* [0], 6.7.5 Declarators */ + /*yy:field Linkage Linkage */ + /*yy:field Read int */ + /*yy:field StorageClass StorageClass */ + /*yy:field Write int */ + /*yy:field funcDefinition *FunctionDefinition */ + /*yy:field lhs map[*Declarator]struct{} */ + /*yy:field td typeDescriptor */ + /*yy:field typ Type */ + /*yy:field AddressTaken bool */ + /*yy:field IsParameter bool */ + /*yy:field IsTypedefName bool */ + /*yy:field SubjectOfAsgnOp bool */ + /*yy:field SubjectOfIncDec bool */ + /*yy:field called bool */ + /*yy:field fnDef bool */ + /*yy:field hasInitializer bool */ + /*yy:field implicit bool */ + /*yy:example int *p __attribute__ ((foo)); */ + Declarator: + Pointer DirectDeclarator AttributeSpecifierList %prec BELOW_ATTRIBUTE + + /* [2], 6.7.5 Alignment specifier */ + /*yy:example _Alignas(double) char c; */ +/*yy:case AlignasType*/ AlignmentSpecifier: + "_Alignas" '(' TypeName ')' + /*yy:example _Alignas(0ll) char c; */ +/*yy:case AlignasExpr*/ | "_Alignas" '(' ConstantExpression ')' + + /*yy:field lexicalScope Scope */ + /*yy:field paramScope Scope */ + /*yy:field typeQualifiers *typeBase */ + /*yy:field idListNoDeclList bool */ + /*yy:example int i; */ +/*yy:case Ident */ DirectDeclarator: + IDENTIFIER Asm + /*yy:example int (f); */ +/*yy:case Decl */ | '(' AttributeSpecifierList Declarator ')' + /*yy:example int i[const 42]; */ +/*yy:case Arr */ | DirectDeclarator '[' TypeQualifiers AssignmentExpression ']' + /*yy:example int i[static const 42]; */ +/*yy:case StaticArr */ | DirectDeclarator '[' "static" TypeQualifiers AssignmentExpression ']' + /*yy:example int i[const static 42]; */ +/*yy:case ArrStatic */ | DirectDeclarator '[' TypeQualifiers "static" AssignmentExpression ']' + /*yy:example int i[const *]; */ +/*yy:case Star */ | DirectDeclarator '[' TypeQualifiers '*' ']' + /*yy:example int f(int i); */ +/*yy:case FuncParam */ | DirectDeclarator '(' ParameterTypeList ')' + /*yy:example int f(a); */ +/*yy:case FuncIdent */ | DirectDeclarator '(' IdentifierList ')' + + /*yy:field typeQualifiers *typeBase*/ + /*yy:example int *p; */ +/*yy:case TypeQual */ Pointer: + '*' TypeQualifiers + /*yy:example int **p; */ +/*yy:case Ptr */ | '*' TypeQualifiers Pointer + /*yy:example int atexit_b(void (^ _Nonnull)(void)); */ +/*yy:case Block */ | '^' TypeQualifiers + + /*yy:field noStorageClass */ + /*yy:example int * const i; */ +/*yy:case TypeQual */ TypeQualifiers: + TypeQualifier + /*yy:example int * __attribute__((a)) i; */ +/*yy:case Attribute */ | AttributeSpecifier + /*yy:example int * const volatile i; */ + | TypeQualifiers TypeQualifier + /*yy:example int * __attribute__((a)) __attribute__((b)) i; */ + | TypeQualifiers AttributeSpecifier + + /*yy:example int f(int i) {} */ +/*yy:case List */ ParameterTypeList: + ParameterList + /*yy:example int f(int i, ...) {} */ +/*yy:case Var */ | ParameterList ',' "..." + + /*yy:example int f(int i) {} */ + ParameterList: + ParameterDeclaration + /*yy:example int f(int i, int j) {} */ + | ParameterList ',' ParameterDeclaration + + /*yy:field typ Type */ + /*yy:example int f(int i) {} */ +/*yy:case Decl */ ParameterDeclaration: + DeclarationSpecifiers Declarator AttributeSpecifierList + /*yy:example int f(int*) {} */ +/*yy:case Abstract */ | DeclarationSpecifiers AbstractDeclarator + + /*yy:field lexicalScope Scope */ + /*yy:example int f(i) int i; {}*/ + IdentifierList: + IDENTIFIER + /*yy:example int f(i, j) int i, j; {}*/ + | IdentifierList ',' IDENTIFIER + + /* [0], 6.7.6 Type names */ + /*yy:field typ Type */ + /*yy:example int i = (int)x; */ + TypeName: + SpecifierQualifierList AbstractDeclarator + + /*yy:field typ Type */ + /*yy:example void f(int*); */ +/*yy:case Ptr */ AbstractDeclarator: + Pointer + /*yy:example void f(int()); */ +/*yy:case Decl */ | Pointer DirectAbstractDeclarator + + /*yy:field paramScope Scope */ + /*yy:field typeQualifiers *typeBase */ + /*yy:example void f(int()); */ +/*yy:case Decl */ DirectAbstractDeclarator: + '(' AbstractDeclarator ')' + /*yy:example void f(int[const 42]); */ +/*yy:case Arr */ | DirectAbstractDeclarator '[' TypeQualifiers AssignmentExpression ']' + /*yy:example void f(int[static const 42]); */ +/*yy:case StaticArr */ | DirectAbstractDeclarator '[' "static" TypeQualifiers AssignmentExpression ']' + /*yy:example void f(int[const static 42]); */ +/*yy:case ArrStatic */ | DirectAbstractDeclarator '[' TypeQualifiers "static" AssignmentExpression ']' + /*yy:example void f(int[*]); */ +/*yy:case ArrStar */ | DirectAbstractDeclarator '[' '*' ']' + /*yy:example void f(int(char)); */ +/*yy:case Func */ | DirectAbstractDeclarator '(' ParameterTypeList ')' + + /* [0], 6.7.8 Initialization */ + /*yy:field Field Field // Where aplicable */ + /*yy:field Offset uintptr // Case Expr */ + /*yy:field field0 Field */ + /*yy:field list []*Initializer */ + /*yy:field parent *Initializer */ + /*yy:field trailingComma *Token */ + /*yy:field typ Type */ + /*yy:field isConst bool */ + /*yy:field isZero bool */ + /*yy:example int i = x; */ +/*yy:case Expr */ Initializer: + AssignmentExpression + /*yy:example int i[] = { x }; */ +/*yy:case InitList */ | '{' InitializerList ',' '}' + + /*yy:field list []*Initializer */ + /*yy:field isConst bool */ + /*yy:field isZero bool */ + /*yy:example int i[] = { [10] = x }; */ + InitializerList: + Designation Initializer + /*yy:example int i[] = { [10] = x, [20] = y }; */ + | InitializerList ',' Designation Initializer + + /*yy:example int a[] = { [42] = 314 }; */ + Designation: + DesignatorList '=' + + /*yy:example int a[] = { [42] = 314 }; */ + DesignatorList: + Designator + /*yy:example int a[100][] = { [42][12] = 314 }; */ + | DesignatorList Designator + + /*yy:field lexicalScope Scope */ + /*yy:example int a[] = { [42] = 314 }; */ +/*yy:case Index */ Designator: + '[' ConstantExpression ']' + /*yy:example struct t s = { .fld = 314 }; */ +/*yy:case Field */ | '.' IDENTIFIER + /*yy:example struct t s = { fld: 314 }; */ +/*yy:case Field2 */ | IDENTIFIER ':' + + /* [0], 6.8 Statements and blocks */ + /*yy:field Operand Operand // Case CompoundStatement, ExpressionStatement*/ + /*yy:example int f() { L: x(); }*/ +/*yy:case Labeled */ Statement: + LabeledStatement + /*yy:example int f() { { y(); } }*/ +/*yy:case Compound */ | CompoundStatement + /*yy:example int f() { x(); }*/ +/*yy:case Expr */ | ExpressionStatement + /*yy:example int f() { if(x) y(); }*/ +/*yy:case Selection */ | SelectionStatement + /*yy:example int f() { for(;;) x(); }*/ +/*yy:case Iteration */ | IterationStatement + /*yy:example int f() { return x; }*/ +/*yy:case Jump */ | JumpStatement + /*yy:example int f() { __asm__("nop"); }*/ +/*yy:case Asm */ | AsmStatement + + /* [0], 6.8.1 Labeled statements */ + /*yy:field block *CompoundStatement */ + /*yy:field lexicalScope Scope */ + /*yy:example int f() { L: goto L; } */ +/*yy:case Label */ LabeledStatement: + IDENTIFIER ':' AttributeSpecifierList Statement + /*yy:example int f() { switch(i) case 42: x(); } */ +/*yy:case CaseLabel */ | "case" ConstantExpression ':' Statement + /*yy:example int f() { switch(i) case 42 ... 56: x(); } */ +/*yy:case Range */ | "case" ConstantExpression "..." ConstantExpression ':' Statement + /*yy:example int f() { switch(i) default: x(); } */ +/*yy:case Default */ | "default" ':' Statement + + /* [0], 6.8.2 Compound statement */ + /*yy:field Operand Operand */ + /*yy:field children []*CompoundStatement */ + /*yy:field declarations []*Declaration */ + /*yy:field isJumpTarget bool */ + /*yy:field labeledStmts []*LabeledStatement */ + /*yy:field parent *CompoundStatement */ + /*yy:field scope Scope */ + /*yy:example int f() { int i; } */ + CompoundStatement: + '{' BlockItemList '}' + + /*yy:example int f() { int i; }*/ + BlockItemList: + BlockItem + /*yy:example int f() { int i; double j; }*/ + | BlockItemList BlockItem + + /*yy:field fn *FunctionDefinition // Case FuncDef */ + /*yy:field closure map[StringID]struct{} // Case FuncDef */ + /*yy:field Last bool */ + /*yy:example int f() { int i; }*/ +/*yy:case Decl */ BlockItem: + Declaration + /*yy:example int f() { g(); }*/ +/*yy:case Stmt */ | Statement + /*yy:example int f() { __label__ L; }*/ +/*yy:case Label */ | LabelDeclaration + /*yy:example int f() { int g() {} }*/ +/*yy:case FuncDef */ | DeclarationSpecifiers Declarator CompoundStatement + /*yy:example int f() {\n#pragma STDC FENV_ACCESS OFF\n}*/ +/*yy:case Pragma */ | PragmaSTDC + + /* [0], 6.8.3 Expression and null statements */ + /*yy:example int f() { g(); }*/ + ExpressionStatement: + Expression AttributeSpecifierList ';' + + /* [0], 6.8.4 Selection statements */ + /*yy:field promote Type // switch expression promoted type */ + /*yy:field cases []*LabeledStatement */ + /*yy:example int f() { if(x) y(); } */ +/*yy:case If */ SelectionStatement: + "if" '(' Expression ')' Statement %prec BELOW_ELSE + /*yy:example int f() { if(x) y(); else z(); } */ +/*yy:case IfElse */ | "if" '(' Expression ')' Statement "else" Statement + /*yy:example int f() { switch(i) case 42: x(); } */ +/*yy:case Switch */ | "switch" '(' Expression ')' Statement + + /* [0], 6.8.5 Iteration statements */ + /*yy:example int f() { while(x) y(); } */ +/*yy:case While */ IterationStatement: + "while" '(' Expression ')' Statement + /*yy:example int f() { do x(); while(y); } */ +/*yy:case Do */ | "do" Statement "while" '(' Expression ')' ';' + /*yy:example int f() { for( i = 0; i < 10; i++) x(); } */ +/*yy:case For */ | "for" '(' Expression ';' Expression ';' Expression ')' Statement + /*yy:example int f() { for( int i = 0; i < 10; i++) x(); } */ +/*yy:case ForDecl */ | "for" '(' Declaration Expression ';' Expression ')' Statement + + /* [0], 6.8.6 Jump statements */ + /*yy:field context Node */ + /*yy:field lexicalScope Scope */ + /*yy:example int f() { L: goto L; } */ +/*yy:case Goto */ JumpStatement: + "goto" IDENTIFIER ';' + /*yy:example int f() { L: x(); void *p = &&L; goto *p; } */ +/*yy:case GotoExpr */ | "goto" '*' Expression ';' + /*yy:example int f() { for(;;) if (i) continue; } */ +/*yy:case Continue */ | "continue" ';' + /*yy:example int f() { for(;;) if (i) break; } */ +/*yy:case Break */ | "break" ';' + /*yy:example int f() { if (i) return x; } */ +/*yy:case Return */ | "return" Expression ';' + + /* [0], 6.9 External definitions */ + /*yy:list*/ + /*yy:example int i; */ + TranslationUnit: + ExternalDeclaration + /*yy:example int i; int j; */ + | TranslationUnit ExternalDeclaration + + /*yy:example int f() {} */ +/*yy:case FuncDef */ ExternalDeclaration: + FunctionDefinition + /*yy:example int i; */ +/*yy:case Decl */ | Declaration + /*yy:example int f() __asm__("nop"); */ +/*yy:case Asm */ | AsmFunctionDefinition + /*yy:example __asm__("nop"); */ +/*yy:case AsmStmt */ | AsmStatement + /*yy:example ; */ +/*yy:case Empty */ | ';' + /*yy:example #pragma STDC CX_LIMITED_RANGE DEFAULT */ +/*yy:case Pragma */ | PragmaSTDC + + /* [0], 6.9.1 Function definitions */ + /*yy:field CallSiteComplexExpr []*AssignmentExpression */ + /*yy:field CompositeLiterals []*PostfixExpression */ + /*yy:field ComputedGotos map[StringID]*UnaryExpression */ + /*yy:field Gotos map[StringID]*JumpStatement */ + /*yy:field InitDeclarators []*InitDeclarator */ + /*yy:field Labels map[StringID]*LabeledStatement */ + /*yy:field ReturnComplexExpr []*Expression */ + /*yy:field VLAs []*Declarator */ + /*yy:field compoundStatements []*CompoundStatement */ + /*yy:field checked bool */ + /*yy:example int f() {} */ + FunctionDefinition: + DeclarationSpecifiers Declarator DeclarationList CompoundStatement + + /*yy:example int f(i) int i; {} */ + DeclarationList: + Declaration + /*yy:example int f(i, j) int i; int j; {} */ + | DeclarationList Declaration + + /* -------------------------------------- Extensions */ + + /*yy:example __asm__("nop": [a] b); */ + AsmIndex: + '[' Expression ']' + + /*yy:example __asm__("nop": a); */ + AsmExpressionList: + AsmIndex AssignmentExpression + /*yy:example __asm__("nop": a, b); */ + | AsmExpressionList ',' AsmIndex AssignmentExpression + + /*yy:example __asm__("nop": a); */ + AsmArgList: + ':' AsmExpressionList + /*yy:example __asm__("nop": a : b); */ + | AsmArgList ':' AsmExpressionList + + /*yy:example __asm__("nop"); */ + Asm: + "__asm__" AsmQualifierList '(' STRINGLITERAL AsmArgList ')' + + /*yy:example void f() { __asm__("nop"); } */ + AsmStatement: + Asm AttributeSpecifierList ';' + + /*yy:example int f() __asm__("nop"); */ + AsmFunctionDefinition: + DeclarationSpecifiers Declarator AsmStatement + + /*yy:example __asm__ volatile ("nop"); */ +/*yy:case Volatile */ AsmQualifier: + "volatile" + /*yy:example __asm__ inline ("nop"); */ +/*yy:case Inline */ | "inline" + /*yy:example __asm__ goto ("nop"); */ +/*yy:case Goto */ | "goto" + + /*yy:example __asm__ inline ("nop"); */ + AsmQualifierList: + AsmQualifier + /*yy:example __asm__ inline volatile ("nop"); */ + | AsmQualifierList AsmQualifier + + /*yy:example int f() { __label__ L; L: x(); } */ + LabelDeclaration: + "__label__" IdentifierList ';' + + /* [4], 6.37 Attribute Syntax */ + /*yy:example int i __attribute__((a(b))); */ + ExpressionList: + AssignmentExpression + /*yy:example int i __attribute__((a(b, c))); */ + | ExpressionList ',' AssignmentExpression + + /*yy:field lexicalScope Scope */ + /*yy:example int i __attribute__((a)); */ +/*yy:case Ident */ AttributeValue: + IDENTIFIER + /*yy:example int i __attribute__((a(b))); */ +/*yy:case Expr */ | IDENTIFIER '(' ExpressionList ')' + + /*yy:example int i __attribute__((a)); */ + AttributeValueList: + AttributeValue + /*yy:example int i __attribute__((a, b)); */ + | AttributeValueList ',' AttributeValue + + /*yy:example int i __attribute__((a)); */ + AttributeSpecifier: + "__attribute__" '(' '(' AttributeValueList ')' ')' + + /*yy:example int i __attribute__((a)); */ + AttributeSpecifierList: + AttributeSpecifier %prec BELOW_ATTRIBUTE + /*yy:example int i __attribute__((a)) __attribute((b)); */ + | AttributeSpecifierList AttributeSpecifier + + /*yy:example _Pragma("STDC FP_CONTRACT ON") */ + PragmaSTDC: + "__pragma_stdc" IDENTIFIER IDENTIFIER IDENTIFIER diff --git a/vendor/modernc.org/cc/v3/scanner.go b/vendor/modernc.org/cc/v3/scanner.go new file mode 100644 index 00000000..6217d7db --- /dev/null +++ b/vendor/modernc.org/cc/v3/scanner.go @@ -0,0 +1,1266 @@ +// 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 ( + "bufio" + "bytes" + "fmt" + goscanner "go/scanner" + "io" + "path/filepath" + "strconv" + "strings" + "sync" + "unicode/utf8" + + "modernc.org/mathutil" + "modernc.org/token" +) + +const ( + clsEOF = iota + 0x80 + clsOther +) + +const maxASCII = 0x7f + +var ( + bom = []byte{0xEF, 0xBB, 0xBF} + + idDefine = dict.sid("define") + idElif = dict.sid("elif") + idElse = dict.sid("else") + idEndif = dict.sid("endif") + idError = dict.sid("error") + idIf = dict.sid("if") + idIfdef = dict.sid("ifdef") + idIfndef = dict.sid("ifndef") + idInclude = dict.sid("include") + idIncludeNext = dict.sid("include_next") + idLine = dict.sid("line") + idPragma = dict.sid("pragma") + idPragmaOp = dict.sid("_Pragma") + idSpace = dict.sid(" ") + idUndef = dict.sid("undef") + + trigraphPrefix = []byte("??") + trigraphs = []struct{ from, to []byte }{ + {[]byte("??="), []byte{'#'}}, + {[]byte("??("), []byte{'['}}, + {[]byte("??/"), []byte{'\\'}}, + {[]byte("??)"), []byte{']'}}, + {[]byte("??'"), []byte{'^'}}, + {[]byte("??<"), []byte{'{'}}, + {[]byte("??!"), []byte{'|'}}, + {[]byte("??>"), []byte{'}'}}, + {[]byte("??-"), []byte{'~'}}, + } +) + +type tokenFile struct { + *token.File + sync.RWMutex +} + +func tokenNewFile(name string, sz int) *tokenFile { return &tokenFile{File: token.NewFile(name, sz)} } + +func (f *tokenFile) Position(pos token.Pos) (r token.Position) { + f.RLock() + r = f.File.Position(pos) + f.RUnlock() + return r +} + +func (f *tokenFile) PositionFor(pos token.Pos, adjusted bool) (r token.Position) { + f.RLock() + r = f.File.PositionFor(pos, adjusted) + f.RUnlock() + return r +} + +func (f *tokenFile) AddLine(off int) { + f.Lock() + f.File.AddLine(off) + f.Unlock() +} + +func (f *tokenFile) AddLineInfo(off int, fn string, line int) { + f.Lock() + f.File.AddLineInfo(off, fn, line) + f.Unlock() +} + +type node interface { + Pos() token.Pos +} + +type dictionary struct { + mu sync.RWMutex + m map[string]StringID + strings []string +} + +func newDictionary() (r *dictionary) { + r = &dictionary{m: map[string]StringID{}} + b := make([]byte, 1) + for i := 0; i < 128; i++ { + var s string + if i != 0 { + b[0] = byte(i) + s = string(b) + } + r.m[s] = StringID(i) + r.strings = append(r.strings, s) + dictStrings[i] = s + } + return r +} + +func (d *dictionary) id(key []byte) StringID { + switch len(key) { + case 0: + return 0 + case 1: + if c := key[0]; c != 0 && c < 128 { + return StringID(c) + } + } + + d.mu.Lock() + if n, ok := d.m[string(key)]; ok { + d.mu.Unlock() + return n + } + + n := StringID(len(d.strings)) + s := string(key) + if int(n) < 256 { + dictStrings[n] = s + } + d.strings = append(d.strings, s) + d.m[s] = n + d.mu.Unlock() + return n +} + +func (d *dictionary) sid(key string) StringID { + switch len(key) { + case 0: + return 0 + case 1: + if c := key[0]; c != 0 && c < 128 { + return StringID(c) + } + } + + d.mu.Lock() + if n, ok := d.m[key]; ok { + d.mu.Unlock() + return n + } + + n := StringID(len(d.strings)) + if int(n) < 256 { + dictStrings[n] = key + } + d.strings = append(d.strings, key) + d.m[key] = n + d.mu.Unlock() + return n +} + +type char struct { + pos int32 + c byte +} + +// token3 is produced by translation phase 3. +type token3 struct { + char rune + pos int32 + value StringID + src StringID + macro StringID +} + +func (t token3) Pos() token.Pos { return token.Pos(t.pos) } +func (t token3) String() string { return t.value.String() } + +type scanner struct { + bomFix int + bytesBuf []byte + charBuf []char + ctx *context + file *tokenFile + fileOffset int + firstPos token.Pos + lineBuf []byte + lookaheadChar char + lookaheadLine ppLine + mark int + pos token.Pos + r *bufio.Reader + srcBuf []byte + tokenBuf []token3 + ungetBuf []char + + tok token3 + + closed bool + preserveWhiteSpace bool +} + +func newScanner0(ctx *context, r io.Reader, file *tokenFile, bufSize int) *scanner { + s := &scanner{ + ctx: ctx, + file: file, + r: bufio.NewReaderSize(r, bufSize), + } + if r != nil { + s.init() + } + return s +} + +func newScanner(ctx *context, r io.Reader, file *tokenFile) *scanner { + bufSize := 1 << 17 // emulate gcc + if n := ctx.cfg.MaxSourceLine; n > 4096 { + bufSize = n + } + return newScanner0(ctx, r, file, bufSize) +} + +func (s *scanner) abort() (r byte, b bool) { + if s.mark >= 0 { + if len(s.charBuf) > s.mark { + s.unget(s.lookaheadChar) + for i := len(s.charBuf) - 1; i >= s.mark; i-- { + s.unget(s.charBuf[i]) + } + } + s.charBuf = s.charBuf[:s.mark] + return 0, false + } + + switch n := len(s.charBuf); n { + case 0: // [] z + c := s.lookaheadChar + s.next() + return s.class(c.c), true + case 1: // [a] z + return s.class(s.charBuf[0].c), true + default: // [a, b, ...], z + c := s.charBuf[0] // a + s.unget(s.lookaheadChar) // z + for i := n - 1; i > 1; i-- { + s.unget(s.charBuf[i]) // ... + } + s.lookaheadChar = s.charBuf[1] // b + s.charBuf = s.charBuf[:1] + return s.class(c.c), true + } +} + +func (s *scanner) class(b byte) byte { + switch { + case b == 0: + return clsEOF + case b > maxASCII: + return clsOther + default: + return b + } +} + +func (s *scanner) err(n node, msg string, args ...interface{}) { s.errPos(n.Pos(), msg, args...) } + +func (s *scanner) errLine(x interface{}, msg string, args ...interface{}) { + var toks []token3 + switch x := x.(type) { + case nil: + toks = []token3{{}} + case ppLine: + toks = x.getToks() + default: + panic(internalError()) + } + var b strings.Builder + for _, v := range toks { + switch v.char { + case '\n': + // nop + case ' ': + b.WriteByte(' ') + default: + b.WriteString(v.String()) + } + } + s.err(toks[0], "%s"+msg, append([]interface{}{b.String()}, args...)...) +} + +func (s *scanner) errPos(pos token.Pos, msg string, args ...interface{}) { + if s.ctx.err(s.file.Position(pos), msg, args...) { + s.r.Reset(nil) + s.closed = true + } +} + +func (s *scanner) init() *scanner { + if s.r == nil { + return s + } + + b, err := s.r.Peek(3) + if err == nil && bytes.Equal(b, bom) { + s.bomFix, _ = s.r.Discard(3) + } + s.tokenBuf = nil + return s +} + +func (s *scanner) initScan() (r byte) { + if s.lookaheadChar.pos == 0 { + s.next() + } + s.firstPos = token.Pos(s.lookaheadChar.pos) + s.mark = -1 + if len(s.charBuf) > 1<<18 { //DONE benchmark tuned + s.bytesBuf = nil + s.charBuf = nil + s.srcBuf = nil + } else { + s.bytesBuf = s.bytesBuf[:0] + s.charBuf = s.charBuf[:0] + s.srcBuf = s.bytesBuf[:0] + } + return s.class(s.lookaheadChar.c) +} + +func (s *scanner) lex() { + s.tok.char = s.scan() + s.tok.pos = int32(s.firstPos) + for _, v := range s.charBuf { + s.srcBuf = append(s.srcBuf, v.c) + } + s.tok.src = dict.id(s.srcBuf) + switch { + case s.tok.char == ' ' && !s.preserveWhiteSpace && !s.ctx.cfg.PreserveWhiteSpace: + s.tok.value = idSpace + case s.tok.char == IDENTIFIER: + for i := 0; i < len(s.charBuf); { + c := s.charBuf[i].c + if c != '\\' { + s.bytesBuf = append(s.bytesBuf, c) + i++ + continue + } + + i++ // Skip '\\' + var n int + switch s.charBuf[i].c { + case 'u': + n = 4 + case 'U': + n = 8 + default: + panic(internalError()) + } + i++ // Skip 'u' or 'U' + l := len(s.bytesBuf) + for i0 := i; i < i0+n; i++ { + s.bytesBuf = append(s.bytesBuf, s.charBuf[i].c) + } + r, err := strconv.ParseUint(string(s.bytesBuf[l:l+n]), 16, 32) + if err != nil { + panic(internalError()) + } + + n2 := utf8.EncodeRune(s.bytesBuf[l:], rune(r)) + s.bytesBuf = s.bytesBuf[:l+n2] + } + s.tok.value = dict.id(s.bytesBuf) + default: + s.tok.value = s.tok.src + } + switch s.tok.char { + case clsEOF: + s.tok.char = -1 + s.tok.pos = int32(s.file.Pos(s.file.Size())) + } + // dbg("lex %q %q", tokName(s.tok.char), s.tok.value) +} + +func (s *scanner) next() (r byte) { + if s.lookaheadChar.pos > 0 { + s.charBuf = append(s.charBuf, s.lookaheadChar) + } + if n := len(s.ungetBuf); n != 0 { + s.lookaheadChar = s.ungetBuf[n-1] + s.ungetBuf = s.ungetBuf[:n-1] + return s.class(s.lookaheadChar.c) + } + + if len(s.lineBuf) == 0 { + more: + if s.closed || s.fileOffset == s.file.Size() { + s.lookaheadChar.c = 0 + s.lookaheadChar.pos = 0 + return clsEOF + } + + b, err := s.r.ReadSlice('\n') + if err != nil { + if err != io.EOF { + s.errPos(s.pos, "error while reading %s: %s", s.file.Name(), err) + } + if len(b) == 0 { + return clsEOF + } + } + + s.file.AddLine(s.fileOffset) + s.fileOffset += s.bomFix + s.bomFix = 0 + s.pos = token.Pos(s.fileOffset) + s.fileOffset += len(b) + + // [0], 5.1.1.2, 1.1 + // + // Physical source file multibyte characters are mapped, in an + // implementation- defined manner, to the source character set + // (introducing new-line characters for end-of-line indicators) + // if necessary. Trigraph sequences are replaced by + // corresponding single-character internal representations. + if !s.ctx.cfg.DisableTrigraphs && bytes.Contains(b, trigraphPrefix) { + for _, v := range trigraphs { + b = bytes.Replace(b, v.from, v.to, -1) + } + } + + // [0], 5.1.1.2, 2 + // + // Each instance of a backslash character (\) immediately + // followed by a new-line character is deleted, splicing + // physical source lines to form logical source lines. Only + // the last backslash on any physical source line shall be + // eligible for being part of such a splice. A source file that + // is not empty shall end in a new-line character, which shall + // not be immediately preceded by a backslash character before + // any such splicing takes place. + s.lineBuf = b + n := len(b) + switch { + case b[n-1] != '\n': + if s.ctx.cfg.RejectMissingFinalNewline { + s.errPos(s.pos+token.Pos(n), "non empty source file shall end in a new-line character") + } + b = append(b[:n:n], '\n') // bufio.Reader owns the bytes + case n > 1 && b[n-2] == '\\': + if n == 2 { + goto more + } + + b = b[:n-2] + n = len(b) + if s.fileOffset == s.file.Size() { + if s.ctx.cfg.RejectFinalBackslash { + s.errPos(s.pos+token.Pos(n+1), "source file final new-line character shall not be preceded by a backslash character") + } + b = append(b[:n:n], '\n') // bufio.Reader owns the bytes + } + case n > 2 && b[n-3] == '\\' && b[n-2] == '\r': + // we've got a windows source that has \r\n line endings. + if n == 3 { + goto more + } + + b = b[:n-3] + n = len(b) + if s.fileOffset == s.file.Size() { + if s.ctx.cfg.RejectFinalBackslash { + s.errPos(s.pos+token.Pos(n+1), "source file final new-line character shall not be preceded by a backslash character") + } + b = append(b[:n:n], '\n') // bufio.Reader owns the bytes + } + } + s.lineBuf = b + } + s.pos++ + s.lookaheadChar = char{int32(s.pos), s.lineBuf[0]} + s.lineBuf = s.lineBuf[1:] + return s.class(s.lookaheadChar.c) +} + +func (s *scanner) unget(c ...char) { + s.ungetBuf = append(s.ungetBuf, c...) + s.lookaheadChar.pos = 0 // Must invalidate lookahead. +} + +func (s *scanner) unterminatedComment() rune { + s.errPos(token.Pos(s.file.Size()), "unterminated comment") + n := len(s.charBuf) + s.unget(s.charBuf[n-1]) // \n + s.charBuf = s.charBuf[:n-1] + return ' ' +} + +// -------------------------------------------------------- Translation phase 3 + +// [0], 5.1.1.2, 3 +// +// The source file is decomposed into preprocessing tokens and sequences of +// white-space characters (including comments). A source file shall not end in +// a partial preprocessing token or in a partial comment. Each comment is +// replaced by one space character. New-line characters are retained. Whether +// each nonempty sequence of white-space characters other than new-line is +// retained or replaced by one space character is implementation-defined. +func (s *scanner) translationPhase3() *ppFile { + r := &ppFile{file: s.file} + if s.file.Size() == 0 { + s.r.Reset(nil) + return r + } + + s.nextLine() + r.groups = s.parseGroup() + return r +} + +func (s *scanner) parseGroup() (r []ppGroup) { + for { + switch x := s.lookaheadLine.(type) { + case ppGroup: + r = append(r, x) + s.nextLine() + case ppIfGroupDirective: + r = append(r, s.parseIfSection()) + default: + return r + } + } +} + +func (s *scanner) parseIfSection() *ppIfSection { + return &ppIfSection{ + ifGroup: s.parseIfGroup(), + elifGroups: s.parseElifGroup(), + elseGroup: s.parseElseGroup(), + endifLine: s.parseEndifLine(), + } +} + +func (s *scanner) parseEndifLine() *ppEndifDirective { + switch x := s.lookaheadLine.(type) { + case *ppEndifDirective: + s.nextLine() + return x + default: + s.errLine(x, fmt.Sprintf(": expected #endif (unexpected %T)", x)) + s.nextLine() + return nil + } +} + +func (s *scanner) parseElseGroup() *ppElseGroup { + switch x := s.lookaheadLine.(type) { + case *ppElseDirective: + r := &ppElseGroup{elseLine: x} + s.nextLine() + r.groups = s.parseGroup() + return r + default: + return nil + } +} + +func (s *scanner) parseElifGroup() (r []*ppElifGroup) { + for { + var g ppElifGroup + switch x := s.lookaheadLine.(type) { + case *ppElifDirective: + g.elif = x + s.nextLine() + g.groups = s.parseGroup() + r = append(r, &g) + default: + return r + } + } +} + +func (s *scanner) parseIfGroup() *ppIfGroup { + r := &ppIfGroup{} + switch x := s.lookaheadLine.(type) { + case ppIfGroupDirective: + r.directive = x + default: + s.errLine(x, fmt.Sprintf(": expected if-group (unexpected %T)", x)) + } + s.nextLine() + r.groups = s.parseGroup() + return r +} + +func (s *scanner) nextLine() { + s.tokenBuf = nil + s.lookaheadLine = s.scanLine() +} + +func (s *scanner) scanLine() (r ppLine) { +again: + toks := s.scanToNonBlankToken(nil) + if len(toks) == 0 { + return nil + } + + includeNext := false + switch tok := toks[len(toks)-1]; tok.char { + case '#': + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppEmptyDirective{toks: toks} + case IDENTIFIER: + switch tok.value { + case idDefine: + return s.parseDefine(toks) + case idElif: + return s.parseElif(toks) + case idElse: + return s.parseElse(toks) + case idEndif: + return s.parseEndif(toks) + case idIf: + return s.parseIf(toks) + case idIfdef: + return s.parseIfdef(toks) + case idIfndef: + return s.parseIfndef(toks) + case idIncludeNext: + includeNext = true + fallthrough + case idInclude: + // # include pp-tokens new-line + // + // Prevent aliasing of eg. <foo bar.h> and <foo bar.h>. + save := s.preserveWhiteSpace + s.preserveWhiteSpace = true + n := len(toks) + toks := s.scanLineToEOL(toks) + r := &ppIncludeDirective{arg: toks[n : len(toks)-1], toks: toks, includeNext: includeNext} + s.preserveWhiteSpace = save + return r + case idUndef: + return s.parseUndef(toks) + case idLine: + return s.parseLine(toks) + case idError: + // # error pp-tokens_opt new-line + n := len(toks) + toks := s.scanLineToEOL(toks) + msg := toks[n : len(toks)-1] + if len(msg) != 0 && msg[0].char == ' ' { + msg = msg[1:] + } + return &ppErrorDirective{toks: toks, msg: msg} + case idPragma: + return s.parsePragma(toks) + } + } + + // # non-directive + return &ppNonDirective{toks: s.scanLineToEOL(toks)} + case '\n': + return &ppTextLine{toks: toks} + case IDENTIFIER: + if tok.value == idPragmaOp { + toks = s.scanToNonBlankToken(toks) + switch tok = toks[len(toks)-1]; tok.char { + case '(': + // ok + default: + s.err(tok, "expected (") + return &ppTextLine{toks: toks} + } + + var lit string + toks = s.scanToNonBlankToken(toks) + switch tok = toks[len(toks)-1]; tok.char { + case STRINGLITERAL: + lit = tok.String() + case LONGSTRINGLITERAL: + lit = tok.String()[1:] // [0], 6.9.10, 1 + default: + s.err(tok, "expected string literal") + return &ppTextLine{toks: toks} + } + + pos := tok.pos + toks = s.scanToNonBlankToken(toks) + switch tok = toks[len(toks)-1]; tok.char { + case ')': + // ok + default: + s.err(tok, "expected )") + return &ppTextLine{toks: toks} + } + + s.unget(s.lookaheadChar) + // [0], 6.9.10, 1 + lit = lit[1 : len(lit)-1] + lit = strings.ReplaceAll(lit, `\"`, `"`) + lit = strings.ReplaceAll(lit, `\\`, `\`) + lit = "#pragma " + lit + "\n" + for i := len(lit) - 1; i >= 0; i-- { + s.unget(char{pos, lit[i]}) + } + goto again + } + + fallthrough + default: + return &ppTextLine{toks: s.scanLineToEOL(toks)} + } +} + +func (s *scanner) parsePragma(toks []token3) *ppPragmaDirective { + toks = s.scanToNonBlankToken(toks) + n := len(toks) + if toks[n-1].char != '\n' { + toks = s.scanLineToEOL(toks) + } + return &ppPragmaDirective{toks: toks, args: toks[n-1:]} +} + +// # line pp-tokens new-line +func (s *scanner) parseLine(toks []token3) *ppLineDirective { + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + s.err(tok, "unexpected new-line") + return &ppLineDirective{toks: toks} + default: + toks := s.scanLineToEOL(toks) + last := toks[len(toks)-1] + r := &ppLineDirective{toks: toks, nextPos: int(last.pos) + len(last.src.String())} + toks = toks[:len(toks)-1] // sans new-line + toks = ltrim3(toks) + toks = toks[1:] // Skip '#' + toks = ltrim3(toks) + toks = toks[1:] // Skip "line" + r.args = ltrim3(toks) + return r + } +} + +func ltrim3(toks []token3) []token3 { + for len(toks) != 0 && toks[0].char == ' ' { + toks = toks[1:] + } + return toks +} + +// # undef identifier new-line +func (s *scanner) parseUndef(toks []token3) *ppUndefDirective { + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + s.err(&tok, "expected identifier") + return &ppUndefDirective{toks: toks} + case IDENTIFIER: + name := tok + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppUndefDirective{name: name, toks: toks} + default: + if s.ctx.cfg.RejectUndefExtraTokens { + s.err(&tok, "extra tokens after #undef") + } + return &ppUndefDirective{name: name, toks: s.scanLineToEOL(toks)} + } + default: + s.err(&tok, "expected identifier") + return &ppUndefDirective{toks: s.scanLineToEOL(toks)} + } +} + +func (s *scanner) scanLineToEOL(toks []token3) []token3 { + n := len(s.tokenBuf) - len(toks) + for { + s.lex() + s.tokenBuf = append(s.tokenBuf, s.tok) + if s.tok.char == '\n' { + return s.tokenBuf[n:] + } + } +} + +// # ifndef identifier new-line +func (s *scanner) parseIfndef(toks []token3) *ppIfndefDirective { + var name StringID + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case IDENTIFIER: + name = tok.value + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppIfndefDirective{name: name, toks: toks} + default: + if s.ctx.cfg.RejectIfndefExtraTokens { + s.err(&tok, "extra tokens after #ifndef") + } + return &ppIfndefDirective{name: name, toks: s.scanLineToEOL(toks)} + } + case '\n': + s.err(tok, "expected identifier") + return &ppIfndefDirective{name: name, toks: toks} + default: + s.err(tok, "expected identifier") + return &ppIfndefDirective{name: name, toks: s.scanLineToEOL(toks)} + } +} + +// # ifdef identifier new-line +func (s *scanner) parseIfdef(toks []token3) *ppIfdefDirective { + var name StringID + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case IDENTIFIER: + name = tok.value + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppIfdefDirective{name: name, toks: toks} + default: + if s.ctx.cfg.RejectIfdefExtraTokens { + s.err(&tok, "extra tokens after #ifdef") + } + return &ppIfdefDirective{name: name, toks: s.scanLineToEOL(toks)} + } + case '\n': + s.err(tok, "expected identifier") + return &ppIfdefDirective{name: name, toks: toks} + default: + s.err(tok, "expected identifier") + return &ppIfdefDirective{name: name, toks: s.scanLineToEOL(toks)} + } +} + +// # if constant-expression new-line +func (s *scanner) parseIf(toks []token3) *ppIfDirective { + n := len(toks) + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + s.err(tok, "expected expression") + return &ppIfDirective{toks: toks} + default: + toks = s.scanLineToEOL(toks) + expr := toks[n:] + if expr[0].char == ' ' { // sans leading space + expr = expr[1:] + } + expr = expr[:len(expr)-1] // sans '\n' + return &ppIfDirective{toks: toks, expr: expr} + } +} + +// # endif new-line +func (s *scanner) parseEndif(toks []token3) *ppEndifDirective { + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppEndifDirective{toks} + default: + if s.ctx.cfg.RejectEndifExtraTokens { + s.err(&tok, "extra tokens after #else") + } + return &ppEndifDirective{s.scanLineToEOL(toks)} + } +} + +// # else new-line +func (s *scanner) parseElse(toks []token3) *ppElseDirective { + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppElseDirective{toks} + default: + if s.ctx.cfg.RejectElseExtraTokens { + s.err(&tok, "extra tokens after #else") + } + return &ppElseDirective{s.scanLineToEOL(toks)} + } +} + +// # elif constant-expression new-line +func (s *scanner) parseElif(toks []token3) *ppElifDirective { + n := len(toks) + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + s.err(tok, "expected expression") + return &ppElifDirective{toks, nil} + default: + toks = s.scanLineToEOL(toks) + expr := toks[n:] + if expr[0].char == ' ' { // sans leading space + expr = expr[1:] + } + expr = expr[:len(expr)-1] // sans '\n' + return &ppElifDirective{toks, expr} + } +} + +func (s *scanner) parseDefine(toks []token3) ppLine { + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case IDENTIFIER: + name := tok + n := len(toks) + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + return &ppDefineObjectMacroDirective{name: name, toks: toks} + case '(': + if toks[n].char == ' ' { + return s.parseDefineObjectMacro(n, name, toks) + } + + return s.parseDefineFunctionMacro(name, toks) + default: + return s.parseDefineObjectMacro(n, name, toks) + } + case '\n': + s.err(tok, "expected identifier") + return &ppDefineObjectMacroDirective{toks: toks} + default: + s.err(tok, "expected identifier") + return &ppDefineObjectMacroDirective{toks: s.scanLineToEOL(toks)} + } +} + +// # define identifier lparen identifier-list_opt ) replacement-list new-line +// # define identifier lparen ... ) replacement-list new-line +// # define identifier lparen identifier-list , ... ) replacement-list new-line +func (s *scanner) parseDefineFunctionMacro(name token3, toks []token3) *ppDefineFunctionMacroDirective { + // Parse parameters after "#define name(". + var list []token3 + variadic := false + namedVariadic := false +again: + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case IDENTIFIER: + more: + list = append(list, tok) + toks = s.scanToNonBlankToken(toks) + switch tok = toks[len(toks)-1]; tok.char { + case ',': + toks = s.scanToNonBlankToken(toks) + switch tok = toks[len(toks)-1]; tok.char { + case IDENTIFIER: + goto more + case DDD: + if toks, variadic = s.parseDDD(toks); !variadic { + goto again + } + case ')': + s.err(tok, "expected parameter name") + default: + s.err(tok, "unexpected %q", &tok) + } + case DDD: + namedVariadic = true + if s.ctx.cfg.RejectInvalidVariadicMacros { + s.err(tok, "expected comma") + } + if toks, variadic = s.parseDDD(toks); !variadic { + goto again + } + case ')': + // ok + case '\n': + s.err(tok, "unexpected new-line") + return &ppDefineFunctionMacroDirective{toks: toks} + case IDENTIFIER: + s.err(tok, "expected comma") + goto more + default: + s.err(tok, "unexpected %q", &tok) + } + case DDD: + if toks, variadic = s.parseDDD(toks); !variadic { + goto again + } + case ',': + s.err(tok, "expected parameter name") + goto again + case ')': + // ok + default: + s.err(tok, "expected parameter name") + goto again + } + // Parse replacement list. + n := len(toks) + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case '\n': + if s.ctx.cfg.RejectFunctionMacroEmptyReplacementList { + s.err(tok, "expected replacement list") + } + return &ppDefineFunctionMacroDirective{name: name, identifierList: list, toks: toks, variadic: variadic, namedVariadic: namedVariadic} + default: + toks = s.scanLineToEOL(toks) + repl := toks[n:] // sans #define identifier + repl = repl[:len(repl)-1] // sans '\n' + // 6.10.3, 7 + // + // Any white-space characters preceding or following the + // replacement list of preprocessing tokens are not considered + // part of the replacement list for either form of macro. + repl = trim3(repl) + repl = normalizeHashes(repl) + return &ppDefineFunctionMacroDirective{name: name, identifierList: list, toks: toks, replacementList: repl, variadic: variadic, namedVariadic: namedVariadic} + } +} + +func isWhite(char rune) bool { + switch char { + case ' ', '\t', '\n', '\v', '\f': + return true + } + return false +} + +func trim3(toks []token3) []token3 { + for len(toks) != 0 && isWhite(toks[0].char) { + toks = toks[1:] + } + for len(toks) != 0 && isWhite(toks[len(toks)-1].char) { + toks = toks[:len(toks)-1] + } + return toks +} + +func normalizeHashes(toks []token3) []token3 { + w := 0 + var last rune + for _, v := range toks { + switch { + case v.char == PPPASTE: + if isWhite(last) { + w-- + } + case isWhite(v.char): + if last == '#' || last == PPPASTE { + continue + } + } + last = v.char + toks[w] = v + w++ + } + return toks[:w] +} + +func (s *scanner) parseDDD(toks []token3) ([]token3, bool) { + toks = s.scanToNonBlankToken(toks) + switch tok := toks[len(toks)-1]; tok.char { + case ')': + return toks, true + default: + s.err(tok, "expected right parenthesis") + return toks, false + } +} + +// # define identifier replacement-list new-line +func (s *scanner) parseDefineObjectMacro(n int, name token3, toks []token3) *ppDefineObjectMacroDirective { + toks = s.scanLineToEOL(toks) + repl := toks[n:] // sans #define identifier + repl = repl[:len(repl)-1] // sans '\n' + // 6.10.3, 7 + // + // Any white-space characters preceding or following the replacement + // list of preprocessing tokens are not considered part of the + // replacement list for either form of macro. + repl = trim3(repl) + repl = normalizeHashes(repl) + return &ppDefineObjectMacroDirective{name: name, toks: toks, replacementList: repl} +} + +// Return {}, {x} or {' ', x} +func (s *scanner) scanToNonBlankToken(toks []token3) []token3 { + n := len(s.tokenBuf) - len(toks) + for { + s.lex() + if s.tok.char < 0 { + return s.tokenBuf[n:] + } + + s.tokenBuf = append(s.tokenBuf, s.tok) + if s.tok.char != ' ' { + return s.tokenBuf[n:] + } + } +} + +// ---------------------------------------------------------------------- Cache + +// Translation phase4 source. +type source interface { + ppFile() (*ppFile, error) +} + +type cachedPPFile struct { + err error + errs goscanner.ErrorList + modTime int64 // time.Time.UnixNano() + pf *ppFile + readyCh chan struct{} + size int +} + +func (c *cachedPPFile) ready() *cachedPPFile { close(c.readyCh); return c } +func (c *cachedPPFile) waitFor() (*cachedPPFile, error) { <-c.readyCh; return c, c.err } + +func (c *cachedPPFile) ppFile() (*ppFile, error) { + c.waitFor() + if c.err == nil { + return c.pf, nil + } + + return nil, c.err +} + +type cacheKey struct { + name StringID + sys bool + value StringID + Config3 +} + +type ppCache struct { + mu sync.RWMutex + m map[cacheKey]*cachedPPFile +} + +func newPPCache() *ppCache { return &ppCache{m: map[cacheKey]*cachedPPFile{}} } + +func (c *ppCache) get(ctx *context, src Source) (source, error) { + if src.Value != "" { + return c.getValue(ctx, src.Name, src.Value, false, src.DoNotCache) + } + + return c.getFile(ctx, src.Name, false, src.DoNotCache) +} + +func (c *ppCache) getFile(ctx *context, name string, sys bool, doNotCache bool) (*cachedPPFile, error) { + fi, err := ctx.statFile(name, sys) + if err != nil { + return nil, err + } + + if !fi.Mode().IsRegular() { + return nil, fmt.Errorf("%s is not a regular file", name) + } + + if fi.Size() > mathutil.MaxInt { + return nil, fmt.Errorf("%s: file too big", name) + } + + size := int(fi.Size()) + if !filepath.IsAbs(name) { // Never cache relative paths + f, err := ctx.openFile(name, sys) + if err != nil { + return nil, err + } + + defer f.Close() + + tf := tokenNewFile(name, size) + ppFile := newScanner(ctx, f, tf).translationPhase3() + cf := &cachedPPFile{pf: ppFile, readyCh: make(chan struct{})} + cf.ready() + return cf, nil + } + + modTime := fi.ModTime().UnixNano() + key := cacheKey{dict.sid(name), sys, 0, ctx.cfg.Config3} + c.mu.Lock() + if cf, ok := c.m[key]; ok { + if modTime <= cf.modTime && size == cf.size { + c.mu.Unlock() + if cf.err != nil { + return nil, cf.err + } + + r, err := cf.waitFor() + ctx.errs(cf.errs) + return r, err + } + + delete(c.m, key) + } + + tf := tokenNewFile(name, size) + cf := &cachedPPFile{modTime: modTime, size: size, readyCh: make(chan struct{})} + if !doNotCache { + c.m[key] = cf + } + c.mu.Unlock() + + go func() { + defer cf.ready() + + f, err := ctx.openFile(name, sys) + if err != nil { + cf.err = err + return + } + + defer f.Close() + + ctx2 := newContext(ctx.cfg) + cf.pf = newScanner(ctx2, f, tf).translationPhase3() + cf.errs = ctx2.ErrorList + ctx.errs(cf.errs) + }() + + return cf.waitFor() +} + +func (c *ppCache) getValue(ctx *context, name, value string, sys bool, doNotCache bool) (*cachedPPFile, error) { + key := cacheKey{dict.sid(name), sys, dict.sid(value), ctx.cfg.Config3} + c.mu.Lock() + if cf, ok := c.m[key]; ok { + c.mu.Unlock() + if cf.err != nil { + return nil, cf.err + } + + r, err := cf.waitFor() + ctx.errs(cf.errs) + return r, err + } + + tf := tokenNewFile(name, len(value)) + cf := &cachedPPFile{readyCh: make(chan struct{})} + if !doNotCache { + c.m[key] = cf + } + c.mu.Unlock() + ctx2 := newContext(ctx.cfg) + cf.pf = newScanner(ctx2, strings.NewReader(value), tf).translationPhase3() + cf.errs = ctx2.ErrorList + ctx.errs(cf.errs) + cf.ready() + return cf.waitFor() +} diff --git a/vendor/modernc.org/cc/v3/stringer.go b/vendor/modernc.org/cc/v3/stringer.go new file mode 100644 index 00000000..66b888ae --- /dev/null +++ b/vendor/modernc.org/cc/v3/stringer.go @@ -0,0 +1,99 @@ +// Code generated by "stringer -output stringer.go -linecomment -type=Kind,Linkage"; DO NOT EDIT. + +package cc + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[Invalid-0] + _ = x[Array-1] + _ = x[Bool-2] + _ = x[Char-3] + _ = x[ComplexChar-4] + _ = x[ComplexDouble-5] + _ = x[ComplexFloat-6] + _ = x[ComplexInt-7] + _ = x[ComplexLong-8] + _ = x[ComplexLongDouble-9] + _ = x[ComplexLongLong-10] + _ = x[ComplexShort-11] + _ = x[ComplexUInt-12] + _ = x[ComplexULong-13] + _ = x[ComplexULongLong-14] + _ = x[ComplexUShort-15] + _ = x[Decimal128-16] + _ = x[Decimal32-17] + _ = x[Decimal64-18] + _ = x[Double-19] + _ = x[Enum-20] + _ = x[Float-21] + _ = x[Float128-22] + _ = x[Float32-23] + _ = x[Float32x-24] + _ = x[Float64-25] + _ = x[Float64x-26] + _ = x[Function-27] + _ = x[Int-28] + _ = x[Int8-29] + _ = x[Int16-30] + _ = x[Int32-31] + _ = x[Int64-32] + _ = x[Int128-33] + _ = x[Long-34] + _ = x[LongDouble-35] + _ = x[LongLong-36] + _ = x[Ptr-37] + _ = x[SChar-38] + _ = x[Short-39] + _ = x[Struct-40] + _ = x[TypedefName-41] + _ = x[UChar-42] + _ = x[UInt-43] + _ = x[UInt8-44] + _ = x[UInt16-45] + _ = x[UInt32-46] + _ = x[UInt64-47] + _ = x[UInt128-48] + _ = x[ULong-49] + _ = x[ULongLong-50] + _ = x[UShort-51] + _ = x[Union-52] + _ = x[Void-53] + _ = x[Vector-54] + _ = x[typeofExpr-55] + _ = x[typeofType-56] + _ = x[maxKind-57] +} + +const _Kind_name = "InvalidT[]_Boolcharcomplex charcomplex doublecomplex floatcomplex intcomplex longcomplex long doublecomplex long longcomplex shortcomplex unsignedcomplex unsigned longcomplex unsigned long longcomplex shor_Decimal128_Decimal32_Decimal64doubleenumfloat_Float128_Float32_Float32x_Float64_Float64xfunctionint__int8__int16__int32__int64__int128longlong doublelong longpointersigned charshortstructtypedefnameunsigned charunsignedunsigned __int8unsigned __int16unsigned __int32unsigned __int64unsigned __int128unsigned longunsigned long longunsigned shortunionvoidvectortypeofExprtypeofTypemaxKind" + +var _Kind_index = [...]uint16{0, 7, 10, 15, 19, 31, 45, 58, 69, 81, 100, 117, 130, 146, 167, 193, 205, 216, 226, 236, 242, 246, 251, 260, 268, 277, 285, 294, 302, 305, 311, 318, 325, 332, 340, 344, 355, 364, 371, 382, 387, 393, 404, 417, 425, 440, 456, 472, 488, 505, 518, 536, 550, 555, 559, 565, 575, 585, 592} + +func (i Kind) String() string { + if i >= Kind(len(_Kind_index)-1) { + return "Kind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Kind_name[_Kind_index[i]:_Kind_index[i+1]] +} +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[None-0] + _ = x[Internal-1] + _ = x[External-2] +} + +const _Linkage_name = "NoneInternalExternal" + +var _Linkage_index = [...]uint8{0, 4, 12, 20} + +func (i Linkage) String() string { + if i < 0 || i >= Linkage(len(_Linkage_index)-1) { + return "Linkage(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Linkage_name[_Linkage_index[i]:_Linkage_index[i+1]] +} diff --git a/vendor/modernc.org/cc/v3/type.go b/vendor/modernc.org/cc/v3/type.go new file mode 100644 index 00000000..f339f368 --- /dev/null +++ b/vendor/modernc.org/cc/v3/type.go @@ -0,0 +1,3266 @@ +// 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. + +// Parts of the documentation are modified versions originating in the Go +// project, particularly the reflect package, license of which is reproduced +// below. +// ---------------------------------------------------------------------------- +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the GO-LICENSE file. + +package cc // import "modernc.org/cc/v3" + +import ( + "bytes" + "fmt" + "math" + "sort" + "strings" + "sync" +) + +var ( + _ Field = (*field)(nil) + + _ Type = (*aliasType)(nil) + _ Type = (*arrayType)(nil) + _ Type = (*attributedType)(nil) + _ Type = (*bitFieldType)(nil) + _ Type = (*functionType)(nil) + _ Type = (*pointerType)(nil) + _ Type = (*structType)(nil) + _ Type = (*taggedType)(nil) + _ Type = (*typeBase)(nil) + _ Type = (*vectorType)(nil) + _ Type = noType + + bytesBufferPool = sync.Pool{New: func() interface{} { return &bytes.Buffer{} }} + + idBool = dict.sid("_Bool") + idImag = dict.sid("imag") + idReal = dict.sid("real") + idVectorSize = dict.sid("vector_size") + idVectorSize2 = dict.sid("__vector_size__") + + noType = &typeBase{} + + _ typeDescriptor = (*DeclarationSpecifiers)(nil) + _ typeDescriptor = (*SpecifierQualifierList)(nil) + _ typeDescriptor = (*TypeQualifiers)(nil) + _ typeDescriptor = noTypeDescriptor + + noTypeDescriptor = &DeclarationSpecifiers{} + + // [0]6.3.1.1-1 + // + // Every integer type has an integer conversion rank defined as + // follows: + intConvRank = [maxKind]int{ // Keep Bool first and sorted by rank. + Bool: 1, + Char: 2, + SChar: 2, + UChar: 2, + Short: 3, + UShort: 3, + Int: 4, + UInt: 4, + Long: 5, + ULong: 5, + LongLong: 6, + ULongLong: 6, + Int128: 7, + UInt128: 7, + } + + complexIntegerTypes = [maxKind]bool{ + ComplexChar: true, + ComplexInt: true, + ComplexLong: true, + ComplexLongLong: true, + ComplexShort: true, + ComplexUInt: true, + ComplexULong: true, + ComplexULongLong: true, + ComplexUShort: true, + } + + complexTypes = [maxKind]bool{ + ComplexChar: true, + ComplexDouble: true, + ComplexFloat: true, + ComplexInt: true, + ComplexLong: true, + ComplexLongDouble: true, + ComplexLongLong: true, + ComplexShort: true, + ComplexUInt: true, + ComplexULong: true, + ComplexULongLong: true, + ComplexUShort: true, + } + + integerTypes = [maxKind]bool{ + Bool: true, + Char: true, + Enum: true, + Int: true, + Long: true, + LongLong: true, + SChar: true, + Short: true, + UChar: true, + UInt: true, + ULong: true, + ULongLong: true, + UShort: true, + Int8: true, + Int16: true, + Int32: true, + Int64: true, + Int128: true, + UInt8: true, + UInt16: true, + UInt32: true, + UInt64: true, + UInt128: true, + } + + arithmeticTypes = [maxKind]bool{ + Bool: true, + Char: true, + ComplexChar: true, + ComplexDouble: true, + ComplexFloat: true, + ComplexInt: true, + ComplexLong: true, + ComplexLongDouble: true, + ComplexLongLong: true, + ComplexShort: true, + ComplexUInt: true, + ComplexUShort: true, + Double: true, + Enum: true, + Float: true, + Int: true, + Long: true, + LongDouble: true, + LongLong: true, + SChar: true, + Short: true, + UChar: true, + UInt: true, + ULong: true, + ULongLong: true, + UShort: true, + Int8: true, + Int16: true, + Int32: true, + Int64: true, + Int128: true, + UInt8: true, + UInt16: true, + UInt32: true, + UInt64: true, + UInt128: true, + } + + realTypes = [maxKind]bool{ + Bool: true, + Char: true, + Double: true, + Enum: true, + Float: true, + Int128: true, + Int: true, + Long: true, + LongDouble: true, + LongLong: true, + SChar: true, + Short: true, + UChar: true, + UInt: true, + ULong: true, + ULongLong: true, + UShort: true, + UInt128: true, + } +) + +type noStorageClass struct{} + +func (noStorageClass) auto() bool { return false } +func (noStorageClass) extern() bool { return false } +func (noStorageClass) register() bool { return false } +func (noStorageClass) static() bool { return false } +func (noStorageClass) threadLocal() bool { return false } +func (noStorageClass) typedef() bool { return false } + +// InvalidType creates a new invalid type. +func InvalidType() Type { + return noType +} + +// Type is the representation of a C type. +// +// Not all methods apply to all kinds of types. Restrictions, if any, are noted +// in the documentation for each method. Use the Kind method to find out the +// kind of type before calling kind-specific methods. Calling a method +// inappropriate to the kind of type causes a run-time panic. +// +// Calling a method on a type of kind Invalid yields an undefined result, but +// does not panic. +type Type interface { + //TODO bits() + + // Alias returns the type this type aliases. Non typedef types return + // themselves. + Alias() Type + + // Align returns the alignment in bytes of a value of this type when + // allocated in memory. + Align() int + + // Attributes returns type's attributes, if any. + Attributes() []*AttributeSpecifier + + // UnionCommon reports the kind that unifies all union members, if any, + // or Invalid. For example + // + // union { int i; double d; } + // + // Has no unifying kind and will report kind Invalid, but + // + // union { int *p; double *p; } + // + // will report kind Ptr. + // + // UnionCommon panics if the type's Kind is valid but not Enum. + UnionCommon() Kind + + // Decay returns itself for non array types and the pointer to array + // element otherwise. + Decay() Type + + // Elem returns a type's element type. It panics if the type's Kind is + // valid but not Array or Ptr. + Elem() Type + + // EnumType returns the undelying integer type of an enumerated type. It + // panics if the type's Kind is valid but not Enum. + EnumType() Type + + // BitField returns the associated Field of a type. It panics if the + // type IsBitFieldType returns false. + BitField() Field + + // FieldAlign returns the alignment in bytes of a value of this type + // when used as a field in a struct. + FieldAlign() int + + // FieldByIndex returns the nested field corresponding to the index + // sequence. It is equivalent to calling Field successively for each + // index i. It panics if the type's Kind is valid but not Struct or + // any complex kind. + FieldByIndex(index []int) Field + + // FieldByName returns the struct field with the given name and a + // boolean indicating if the field was found. + FieldByName(name StringID) (Field, bool) + + // FieldByName2 is like FieldByName but additionally returns the + // indices that form the path to the field. + FieldByName2(name StringID) (Field, []int, bool) + + // IsAggregate reports whether type is an aggregate type, [0]6.2.5. + // + // 21) Array and structure types are collectively called aggregate types. + // + // 37) Note that aggregate type does not include union type because an object + // with union type can only contain one member at a time. + IsAggregate() bool + + // IsPacked reports whether type is packed. It panics if the type's + // Kind is valid but not Struct or Union. + IsPacked() bool + + // IsIncomplete reports whether type is incomplete. + IsIncomplete() bool + + // IsComplexIntegerType report whether a type is an integer complex + // type. + IsComplexIntegerType() bool + + // IsComplexType report whether a type is a complex type. + IsComplexType() bool + + // IsArithmeticType report whether a type is an arithmetic type. + IsArithmeticType() bool + + // IsBitFieldType report whether a type is for a bit field. + IsBitFieldType() bool + + // IsIntegerType report whether a type is an integer type. + IsIntegerType() bool + + // IsRealType report whether a type is a real type. + IsRealType() bool + + // IsScalarType report whether a type is a scalar type. + IsScalarType() bool + + // HasFlexibleMember reports whether a struct has a flexible array + // member. It panics if the type's Kind is valid but not Struct or + // Union. + // + // https://en.wikipedia.org/wiki/Flexible_array_member + HasFlexibleMember() bool + + // IsAliasType returns whether a type is an alias name of another type + // For eample + // + // typedef int foo; + // foo x; // The type of x reports true from IsAliasType(). + IsAliasType() bool + + // IsAssingmentCompatible reports whether a type can be assigned from rhs. [0], 6.5.16.1. + IsAssingmentCompatible(rhs Type) bool + + // isAssingmentCompatibleOperand reports whether a type can be assigned from rhs. [0], 6.5.16.1. + isAssingmentCompatibleOperand(rhs Operand) bool + + // IsCompatible reports whether the two types are compatible. [0], 6.2.7. + IsCompatible(Type) bool + + isCompatibleIgnoreQualifiers(Type) bool + + // IsCompatibleLayout reports whether the two types have identical layouts. + IsCompatibleLayout(Type) bool + + // AliasDeclarator returns the typedef declarator of the alias type. It panics + // if the type is not an alias type. + AliasDeclarator() *Declarator + + // IsTaggedType returns whether a type is a tagged reference of a enum, + // struct or union type. For example + // + // struct s { int x; } y; // The type of y reports false from IsTaggedType. + // struct s z; // The type of z reports true from IsTaggedType. + IsTaggedType() bool + + // IsVariadic reports whether a function type is variadic. It panics if + // the type's Kind is valid but not Function. + IsVariadic() bool + + // IsVLA reports whether array is a variable length array. It panics if + // the type's Kind is valid but not Array. + IsVLA() bool + + // Kind returns the specific kind of this type. + Kind() Kind + + // Len returns an array type's length for array types and vector size + // for vector types. It panics if the type's Kind is valid but not + // Array or Vector. + Len() uintptr + + // LenExpr returns an array type's length expression. It panics if the + // type's Kind is valid but not Array or the array is not a VLA. + LenExpr() *AssignmentExpression + + // NumField returns a struct type's field count. It panics if the + // type's Kind is valid but not Struct or any complex kind. + NumField() int + + // Parameters returns the parameters of a function type. It panics if + // the type's Kind is valid but not Function. + Parameters() []*Parameter + + // Real returns the real field of a type. It panics if the type's Kind + // is valid but not a complex kind. + Real() Field + + // Imag returns the imaginary field of a type. It panics if the type's + // Kind is valid but not a complex kind. + Imag() Field + + // Result returns the result type of a function type. It panics if the + // type's Kind is valid but not Function. + Result() Type + + // Size returns the number of bytes needed to store a value of the + // given type. It panics if type is valid but incomplete. + Size() uintptr + + // String implements fmt.Stringer. + String() string + + // Tag returns the tag, of a tagged type or of a struct or union type. + // Tag panics if the type is not tagged type or a struct or union type. + Tag() StringID + + // Name returns type name, if any. + Name() StringID + + // IsAtomic reports whether type has type qualifier "_Atomic". + IsAtomic() bool + + // hasConst reports whether type has type qualifier "const". + hasConst() bool + + // Inline reports whether type has function specifier "inline". + Inline() bool + + IsSignedType() bool + + // noReturn reports whether type has function specifier "_NoReturn". + noReturn() bool + + // restrict reports whether type has type qualifier "restrict". + restrict() bool + + setLen(uintptr) + setFnSpecs(inline, noret bool) + setKind(Kind) + + string(*bytes.Buffer) + + base() typeBase + baseP() *typeBase + + underlyingType() Type + + // IsVolatile reports whether type has type qualifier "volatile". + IsVolatile() bool + + isVectorType() bool +} + +// A Field describes a single field in a struct/union. +type Field interface { + BitFieldBlockFirst() Field + BitFieldBlockWidth() int + BitFieldOffset() int + BitFieldWidth() int + Declarator() *StructDeclarator + InUnion() bool // Directly or indirectly + Index() int + IsBitField() bool + IsFlexible() bool // https://en.wikipedia.org/wiki/Flexible_array_member + Mask() uint64 + Name() StringID // Can be zero. + Offset() uintptr // In bytes from the beginning of the struct/union. + Padding() int // In bytes after the field. N/A for bit fields, fields preceding bit fields or union fields. + Parent() Type // The struct/union type that contains the field. + Promote() Type + Type() Type // Field type. +} + +// A Kind represents the specific kind of type that a Type represents. The zero Kind is not a valid kind. +type Kind uint + +const ( + maxTypeSpecifiers = 4 // eg. long long unsigned int +) + +var ( + validTypeSpecifiers = map[[maxTypeSpecifiers]TypeSpecifierCase]byte{ + + // [2], 6.7.2 Type specifiers, 2. + + //TODO atomic-type-specifier + {TypeSpecifierBool}: byte(Bool), + {TypeSpecifierChar, TypeSpecifierSigned}: byte(SChar), + {TypeSpecifierChar, TypeSpecifierUnsigned}: byte(UChar), + {TypeSpecifierChar}: byte(Char), + {TypeSpecifierDouble, TypeSpecifierComplex}: byte(ComplexDouble), + {TypeSpecifierDouble}: byte(Double), + {TypeSpecifierEnum}: byte(Enum), + {TypeSpecifierFloat, TypeSpecifierComplex}: byte(ComplexFloat), + {TypeSpecifierFloat}: byte(Float), + {TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierSigned}: byte(LongLong), + {TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULongLong), + {TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierLong}: byte(LongLong), + {TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierSigned}: byte(Long), + {TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULong), + {TypeSpecifierInt, TypeSpecifierLong}: byte(Long), + {TypeSpecifierInt, TypeSpecifierSigned}: byte(Int), + {TypeSpecifierInt, TypeSpecifierUnsigned}: byte(UInt), + {TypeSpecifierInt}: byte(Int), + {TypeSpecifierLong, TypeSpecifierDouble, TypeSpecifierComplex}: byte(ComplexLongDouble), + {TypeSpecifierLong, TypeSpecifierDouble}: byte(LongDouble), + {TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierSigned}: byte(LongLong), + {TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULongLong), + {TypeSpecifierLong, TypeSpecifierLong}: byte(LongLong), + {TypeSpecifierLong, TypeSpecifierSigned}: byte(Long), + {TypeSpecifierLong, TypeSpecifierUnsigned}: byte(ULong), + {TypeSpecifierLong}: byte(Long), + {TypeSpecifierShort, TypeSpecifierInt, TypeSpecifierSigned}: byte(Short), + {TypeSpecifierShort, TypeSpecifierInt, TypeSpecifierUnsigned}: byte(UShort), + {TypeSpecifierShort, TypeSpecifierInt}: byte(Short), + {TypeSpecifierShort, TypeSpecifierSigned}: byte(Short), + {TypeSpecifierShort, TypeSpecifierUnsigned}: byte(UShort), + {TypeSpecifierShort}: byte(Short), + {TypeSpecifierSigned}: byte(Int), + {TypeSpecifierStructOrUnion}: byte(Struct), + {TypeSpecifierTypedefName}: byte(TypedefName), //TODO + {TypeSpecifierUnsigned}: byte(UInt), + {TypeSpecifierVoid}: byte(Void), + + // GCC Extensions. + + {TypeSpecifierChar, TypeSpecifierComplex}: byte(ComplexChar), + {TypeSpecifierComplex}: byte(ComplexDouble), + {TypeSpecifierDecimal128}: byte(Decimal128), + {TypeSpecifierDecimal32}: byte(Decimal32), + {TypeSpecifierDecimal64}: byte(Decimal64), + {TypeSpecifierFloat128}: byte(Float128), + {TypeSpecifierFloat32x}: byte(Float32x), + {TypeSpecifierFloat32}: byte(Float32), + {TypeSpecifierFloat64x}: byte(Float64x), + {TypeSpecifierFloat64}: byte(Float64), + {TypeSpecifierInt, TypeSpecifierComplex}: byte(ComplexInt), + {TypeSpecifierInt, TypeSpecifierLong, TypeSpecifierComplex}: byte(ComplexLong), + {TypeSpecifierInt8, TypeSpecifierSigned}: byte(Int8), + {TypeSpecifierInt16, TypeSpecifierSigned}: byte(Int16), + {TypeSpecifierInt32, TypeSpecifierSigned}: byte(Int32), + {TypeSpecifierInt64, TypeSpecifierSigned}: byte(Int64), + {TypeSpecifierInt128, TypeSpecifierSigned}: byte(Int128), + {TypeSpecifierInt8, TypeSpecifierUnsigned}: byte(UInt8), + {TypeSpecifierInt16, TypeSpecifierUnsigned}: byte(UInt16), + {TypeSpecifierInt32, TypeSpecifierUnsigned}: byte(UInt32), + {TypeSpecifierInt64, TypeSpecifierUnsigned}: byte(UInt64), + {TypeSpecifierInt128, TypeSpecifierUnsigned}: byte(UInt128), + {TypeSpecifierInt8}: byte(Int8), + {TypeSpecifierInt16}: byte(Int16), + {TypeSpecifierInt32}: byte(Int32), + {TypeSpecifierInt64}: byte(Int64), + {TypeSpecifierInt128}: byte(Int128), + {TypeSpecifierLong, TypeSpecifierComplex}: byte(ComplexLong), + {TypeSpecifierLong, TypeSpecifierDouble, TypeSpecifierFloat64x}: byte(LongDouble), + {TypeSpecifierLong, TypeSpecifierLong, TypeSpecifierComplex}: byte(ComplexLongLong), + {TypeSpecifierShort, TypeSpecifierComplex}: byte(ComplexUShort), + {TypeSpecifierShort, TypeSpecifierUnsigned, TypeSpecifierComplex}: byte(ComplexShort), + {TypeSpecifierTypeofExpr}: byte(typeofExpr), //TODO + {TypeSpecifierTypeofType}: byte(typeofType), //TODO + {TypeSpecifierUnsigned, TypeSpecifierComplex}: byte(ComplexUInt), + } +) + +type typeDescriptor interface { + Node + auto() bool + extern() bool + register() bool + static() bool + threadLocal() bool + typedef() bool +} + +type storageClass byte + +const ( + fAuto storageClass = 1 << iota + fExtern + fRegister + fStatic + fThreadLocal + fTypedef +) + +type flag uint16 + +const ( + // function specifier + fInline flag = 1 << iota //TODO should go elsewhere + fNoReturn + + // type qualifier + fAtomic + fConst + fRestrict + fVolatile + + // other + fIncomplete + fSigned // Valid only for integer types. + fPacked + fAligned // __attribute__((aligned(n))) applied. +) + +type typeBase struct { + size uintptr + + flags flag + + align byte + fieldAlign byte + kind byte +} + +func (t *typeBase) check(ctx *context, td typeDescriptor, defaultInt bool) (r Type) { + k0 := t.kind + var alignmentSpecifiers []*AlignmentSpecifier + var attributeSpecifiers []*AttributeSpecifier + var typeSpecifiers []*TypeSpecifier + switch n := td.(type) { + case *DeclarationSpecifiers: + for ; n != nil; n = n.DeclarationSpecifiers { + switch n.Case { + case DeclarationSpecifiersStorage: // StorageClassSpecifier DeclarationSpecifiers + // nop + case DeclarationSpecifiersTypeSpec: // TypeSpecifier DeclarationSpecifiers + typeSpecifiers = append(typeSpecifiers, n.TypeSpecifier.list()...) + case DeclarationSpecifiersTypeQual: // TypeQualifier DeclarationSpecifiers + // nop + case DeclarationSpecifiersFunc: // FunctionSpecifier DeclarationSpecifiers + // nop + case DeclarationSpecifiersAlignSpec: // AlignmentSpecifier DeclarationSpecifiers + alignmentSpecifiers = append(alignmentSpecifiers, n.AlignmentSpecifier) + case DeclarationSpecifiersAttribute: // AttributeSpecifier DeclarationSpecifiers + attributeSpecifiers = append(attributeSpecifiers, n.AttributeSpecifier) + default: + panic(internalError()) + } + } + case *SpecifierQualifierList: + for ; n != nil; n = n.SpecifierQualifierList { + switch n.Case { + case SpecifierQualifierListTypeSpec: // TypeSpecifier SpecifierQualifierList + typeSpecifiers = append(typeSpecifiers, n.TypeSpecifier.list()...) + case SpecifierQualifierListTypeQual: // TypeQualifier SpecifierQualifierList + // nop + case SpecifierQualifierListAlignSpec: // AlignmentSpecifier SpecifierQualifierList + alignmentSpecifiers = append(alignmentSpecifiers, n.AlignmentSpecifier) + case SpecifierQualifierListAttribute: // AttributeSpecifier SpecifierQualifierList + attributeSpecifiers = append(attributeSpecifiers, n.AttributeSpecifier) + default: + panic(internalError()) + } + } + case *TypeQualifiers: + for ; n != nil; n = n.TypeQualifiers { + if n.Case == TypeQualifiersAttribute { + attributeSpecifiers = append(attributeSpecifiers, n.AttributeSpecifier) + } + } + default: + panic(internalError()) + } + + if len(typeSpecifiers) > maxTypeSpecifiers { + ctx.err(typeSpecifiers[maxTypeSpecifiers].Position(), "too many type specifiers") + typeSpecifiers = typeSpecifiers[:maxTypeSpecifiers] + } + + sort.Slice(typeSpecifiers, func(i, j int) bool { + return typeSpecifiers[i].Case < typeSpecifiers[j].Case + }) + var k [maxTypeSpecifiers]TypeSpecifierCase + for i, v := range typeSpecifiers { + k[i] = v.Case + } + switch { + case len(typeSpecifiers) == 0: + if !defaultInt { + break + } + + k[0] = TypeSpecifierInt + fallthrough + default: + var ok bool + if t.kind, ok = validTypeSpecifiers[k]; !ok { + s := k[:] + for len(s) > 1 && s[len(s)-1] == TypeSpecifierVoid { + s = s[:len(s)-1] + } + ctx.err(td.Position(), "invalid type specifiers combination: %v", s) + return t + } + + if t.kind == byte(LongDouble) && ctx.cfg.LongDoubleIsDouble { + t.kind = byte(Double) + } + } + switch len(alignmentSpecifiers) { + case 0: + //TODO set alignment from model + case 1: + align := alignmentSpecifiers[0].align() + if align > math.MaxUint8 { + panic(internalError()) + } + t.align = byte(align) + t.fieldAlign = t.align + default: + ctx.err(alignmentSpecifiers[1].Position(), "multiple alignment specifiers") + } + + abi := ctx.cfg.ABI + switch k := t.Kind(); k { + case typeofExpr, typeofType, Struct, Union, Enum: + // nop + default: + if integerTypes[k] && abi.isSignedInteger(k) { + t.flags |= fSigned + } + if v, ok := abi.Types[k]; ok { + t.size = uintptr(abi.size(k)) + if t.align != 0 { + break + } + + t.align = byte(v.Align) + t.fieldAlign = byte(v.FieldAlign) + break + } + + //TODO ctx.err(td.Position(), "missing model item for %s", t.Kind()) + } + + typ := Type(t) + switch k := t.Kind(); k { + case TypedefName: + ts := typeSpecifiers[0] + tok := ts.Token + nm := tok.Value + d := ts.resolvedIn.typedef(nm, tok) + typ = &aliasType{typeBase: t, nm: nm, d: d} + case Enum: + typ = typeSpecifiers[0].EnumSpecifier.typ + case Struct, Union: + t.kind = k0 + typ = typeSpecifiers[0].StructOrUnionSpecifier.typ + case typeofExpr, typeofType: + typ = typeSpecifiers[0].typ + default: + if complexTypes[k] { + typ = ctx.cfg.ABI.Type(k) + } + } + return typ +} + +func (t *typeBase) setAligned(n int) { + t.flags |= fAligned + t.align = byte(n) +} + +// IsAssingmentCompatible implements Type. +func (t *typeBase) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if t == rhs { + return true + } + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + if t.IsArithmeticType() && rhs.IsArithmeticType() { + return true + } + + if x, ok := rhs.(*aliasType); ok { + if x.nm == idBool && rhs.Kind() == Ptr { + return true + } + } + + if t.IsIntegerType() && rhs.Kind() == Ptr { + // 6.3.2.3 Pointers + // + // 6 Any pointer type may be converted to an integer type. Except as previously specified, the + // result is implementation-defined. If the result cannot be represented in the integer type, + // the behavior is undefined. The result need not be in the range of values of any integer + // type. + return true + } + + return false +} + +// isAssingmentCompatibleOperand implements Type. +func (t *typeBase) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + rhsType := rhs.Type().Decay() + if t == rhsType { + return true + } + + return t.IsAssingmentCompatible(rhsType) +} + +// IsCompatible implements Type. +func (t *typeBase) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if !t.IsScalarType() && t.Kind() != Void { + panic(internalErrorf("IsCompatible of invalid type: %v", t.Kind())) + } + + v := u.base() + // [0], 6.7.3 + // + // 9 For two qualified types to be compatible, both shall have the identically + // qualified version of a compatible type; the order of type qualifiers within + // a list of specifiers or qualifiers does not affect the specified type. + if t.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) != v.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) { + return false + } + + if t.Kind() == u.Kind() { + return true + } + + if t.Kind() == Enum && u.IsIntegerType() && t.Size() == u.Size() { + return true + } + + return t.IsIntegerType() && u.Kind() == Enum && t.Size() == u.Size() +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *typeBase) isCompatibleIgnoreQualifiers(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if !t.IsScalarType() && t.Kind() != Void { + panic(internalErrorf("isCompatibleIgnoreQualifiers of invalid type: %v", t.Kind())) + } + + if t.Kind() == u.Kind() { + return true + } + + if t.Kind() == Enum && u.IsIntegerType() && t.Size() == u.Size() { + return true + } + + return t.IsIntegerType() && u.Kind() == Enum && t.Size() == u.Size() +} + +// IsCompatibleLayout implements Type. +func (t *typeBase) IsCompatibleLayout(u Type) bool { + if t == u { + return true + } + + if !t.IsScalarType() { + panic(internalErrorf("%s: IsCompatibleLayout of invalid type", t.Kind())) + } + + if t.Kind() == u.Kind() { + return true + } + + if t.Kind() == Enum && u.IsIntegerType() && t.Size() == u.Size() { + return true + } + + return t.IsIntegerType() && u.Kind() == Enum && t.Size() == u.Size() +} + +// IsPacked implements Type. +func (t *typeBase) IsPacked() bool { + return t.flags&fPacked != 0 +} + +// UnionCommon implements Type. +func (t *typeBase) UnionCommon() Kind { + panic(internalErrorf("%s: UnionCommon of invalid type", t.Kind())) +} + +// IsAtomic implements Type. +func (t *typeBase) IsAtomic() bool { return t.flags&fAtomic != 0 } + +// Attributes implements Type. +func (t *typeBase) Attributes() (a []*AttributeSpecifier) { return nil } + +// Alias implements Type. +func (t *typeBase) Alias() Type { return t } + +// IsAliasType implements Type. +func (t *typeBase) IsAliasType() bool { return false } + +func (t *typeBase) AliasDeclarator() *Declarator { + panic(internalErrorf("%s: AliasDeclarator of invalid type", t.Kind())) +} + +// IsTaggedType implements Type. +func (t *typeBase) IsTaggedType() bool { return false } + +// Align implements Type. +func (t *typeBase) Align() int { return int(t.align) } + +// BitField implements Type. +func (t *typeBase) BitField() Field { + if t.Kind() == Invalid { + return nil + } + + panic(internalErrorf("%s: BitField of invalid type", t.Kind())) +} + +// base implements Type. +func (t *typeBase) base() typeBase { return *t } + +// baseP implements Type. +func (t *typeBase) baseP() *typeBase { return t } + +// isVectorType implements Type. +func (t *typeBase) isVectorType() bool { + return false +} + +// Decay implements Type. +func (t *typeBase) Decay() Type { + if t.Kind() != Array { + return t + } + + panic(internalErrorf("%s: Decay of invalid type", t.Kind())) +} + +// Elem implements Type. +func (t *typeBase) Elem() Type { + if t.Kind() == Invalid { + return t + } + + panic(internalErrorf("%s: Elem of invalid type", t.Kind())) +} + +// EnumType implements Type. +func (t *typeBase) EnumType() Type { + if t.Kind() == Invalid { + return t + } + + panic(internalErrorf("%s: EnumType of invalid type", t.Kind())) +} + +// hasConst implements Type. +func (t *typeBase) hasConst() bool { return t.flags&fConst != 0 } + +// FieldAlign implements Type. +func (t *typeBase) FieldAlign() int { return int(t.fieldAlign) } + +// FieldByIndex implements Type. +func (t *typeBase) FieldByIndex([]int) Field { + if t.Kind() == Invalid { + return nil + } + + panic(internalErrorf("%s: FieldByIndex of invalid type", t.Kind())) +} + +// NumField implements Type. +func (t *typeBase) NumField() int { + if t.Kind() == Invalid { + return 0 + } + + panic(internalErrorf("%s: NumField of invalid type", t.Kind())) +} + +// FieldByName implements Type. +func (t *typeBase) FieldByName(StringID) (Field, bool) { + if t.Kind() == Invalid { + return nil, false + } + + panic(internalErrorf("%s: FieldByName of invalid type", t.Kind())) +} + +// FieldByName2 implements Type. +func (t *typeBase) FieldByName2(StringID) (Field, []int, bool) { + if t.Kind() == Invalid { + return nil, nil, false + } + + panic(internalErrorf("%s: FieldByName2 of invalid type", t.Kind())) +} + +// IsIncomplete implements Type. +func (t *typeBase) IsIncomplete() bool { return t.flags&fIncomplete != 0 } + +// IsAggregate implements Type. +func (t *typeBase) IsAggregate() bool { return t.Kind() == Array || t.Kind() == Struct } + +// Inline implements Type. +func (t *typeBase) Inline() bool { return t.flags&fInline != 0 } + +// IsIntegerType implements Type. +func (t *typeBase) IsIntegerType() bool { return integerTypes[t.kind] } + +// IsArithmeticType implements Type. +func (t *typeBase) IsArithmeticType() bool { return arithmeticTypes[t.Kind()] } + +// IsComplexType implements Type. +func (t *typeBase) IsComplexType() bool { return complexTypes[t.Kind()] } + +// IsComplexIntegerType implements Type. +func (t *typeBase) IsComplexIntegerType() bool { return complexIntegerTypes[t.Kind()] } + +// IsBitFieldType implements Type. +func (t *typeBase) IsBitFieldType() bool { return false } + +// IsRealType implements Type. +func (t *typeBase) IsRealType() bool { return realTypes[t.Kind()] } + +// IsScalarType implements Type. +func (t *typeBase) IsScalarType() bool { + return (t.IsArithmeticType() || t.Kind() == Ptr) && !t.isVectorType() +} + +// HasFlexibleMember implements Type. +func (t *typeBase) HasFlexibleMember() bool { + if t.Kind() == Invalid { + return false + } + + panic(internalErrorf("%s: HasFlexibleMember of invalid type", t.Kind())) +} + +// IsSignedType implements Type. +func (t *typeBase) IsSignedType() bool { + if !integerTypes[t.kind] { + panic(internalErrorf("%s: IsSignedType of non-integer type", t.Kind())) + } + + return t.flags&fSigned != 0 +} + +// IsVariadic implements Type. +func (t *typeBase) IsVariadic() bool { + if t.Kind() == Invalid { + return false + } + + panic(internalErrorf("%s: IsVariadic of invalid type", t.Kind())) +} + +// IsVLA implements Type. +func (t *typeBase) IsVLA() bool { + if t.Kind() == Invalid { + return false + } + + panic(internalErrorf("%s: IsVLA of invalid type", t.Kind())) +} + +// Kind implements Type. +func (t *typeBase) Kind() Kind { return Kind(t.kind) } + +// Len implements Type. +func (t *typeBase) Len() uintptr { panic(internalErrorf("%s: Len of non-array type", t.Kind())) } + +// LenExpr implements Type. +func (t *typeBase) LenExpr() *AssignmentExpression { + panic(internalErrorf("%s: LenExpr of non-array type", t.Kind())) +} + +// noReturn implements Type. +func (t *typeBase) noReturn() bool { return t.flags&fNoReturn != 0 } + +// restrict implements Type. +func (t *typeBase) restrict() bool { return t.flags&fRestrict != 0 } + +// Parameters implements Type. +func (t *typeBase) Parameters() []*Parameter { + if t.Kind() == Invalid { + return nil + } + + panic(internalErrorf("%s: Parameters of invalid type", t.Kind())) +} + +// Result implements Type. +func (t *typeBase) Result() Type { + if t.Kind() == Invalid { + return noType + } + + panic(internalErrorf("%s: Result of invalid type", t.Kind())) +} + +// Real implements Type +func (t *typeBase) Real() Field { + if t.Kind() == Invalid { + return nil + } + + panic(internalErrorf("%s: Real of invalid type", t.Kind())) +} + +// Imag implements Type +func (t *typeBase) Imag() Field { + if t.Kind() == Invalid { + return nil + } + + panic(internalErrorf("%s: Imag of invalid type", t.Kind())) +} + +// Size implements Type. +func (t *typeBase) Size() uintptr { + if t.IsIncomplete() { + panic(internalError()) + } + + return t.size +} + +// setLen implements Type. +func (t *typeBase) setLen(uintptr) { + if t.Kind() == Invalid { + return + } + + panic(internalErrorf("%s: setLen of non-array type", t.Kind())) +} + +// setFnSpecs implements Type. +func (t *typeBase) setFnSpecs(inline, noret bool) { + t.flags &^= fInline | fNoReturn + if inline { + t.flags |= fInline + } + if noret { + t.flags |= fNoReturn + } +} + +// setKind implements Type. +func (t *typeBase) setKind(k Kind) { t.kind = byte(k) } + +// underlyingType implements Type. +func (t *typeBase) underlyingType() Type { return t } + +// IsVolatile implements Type. +func (t *typeBase) IsVolatile() bool { return t.flags&fVolatile != 0 } + +// String implements Type. +func (t *typeBase) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// Name implements Type. +func (t *typeBase) Name() StringID { return 0 } + +// Tag implements Type. +func (t *typeBase) Tag() StringID { + panic(internalErrorf("%s: Tag of invalid type", t.Kind())) +} + +// string implements Type. +func (t *typeBase) string(b *bytes.Buffer) { + spc := "" + if t.IsAtomic() { + b.WriteString("atomic") + spc = " " + } + if t.hasConst() { + b.WriteString(spc) + b.WriteString("const") + spc = " " + } + if t.Inline() { + b.WriteString(spc) + b.WriteString("inline") + spc = " " + } + if t.noReturn() { + b.WriteString(spc) + b.WriteString("_NoReturn") + spc = " " + } + if t.restrict() { + b.WriteString(spc) + b.WriteString("restrict") + spc = " " + } + if t.IsVolatile() { + b.WriteString(spc) + b.WriteString("volatile") + spc = " " + } + b.WriteString(spc) + switch k := t.Kind(); k { + case Enum: + b.WriteString("enum") + case Invalid: + // nop + case Struct: + b.WriteString("struct") + case Union: + b.WriteString("union") + case Ptr: + b.WriteString("pointer") + case typeofExpr, typeofType: + panic(internalError()) + default: + b.WriteString(k.String()) + } +} + +type attributedType struct { + Type + attr []*AttributeSpecifier +} + +// Alias implements Type. +func (t *attributedType) Alias() Type { return t } + +// String implements Type. +func (t *attributedType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// string implements Type. +func (t *attributedType) string(b *bytes.Buffer) { + t.Type.string(b) + for _, v := range t.attr { + b.WriteString(nodeSource(v)) + } +} + +// Attributes implements Type. +func (t *attributedType) Attributes() []*AttributeSpecifier { return t.attr } + +type pointerType struct { + typeBase + + elem Type + typeQualifiers Type +} + +// IsAssingmentCompatible implements Type. +func (t *pointerType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if rhs = rhs.Alias().Decay(); t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + + if rhs.Kind() == Ptr { + v := rhs.(*pointerType) + a := t.Elem().Alias().Decay() + b := v.Elem().Alias().Decay() + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + if a.Kind() == Void || b.Kind() == Void { + return true + } + + x := a.base().flags & (fAtomic | fConst | fRestrict | fVolatile) + y := b.base().flags & (fAtomic | fConst | fRestrict | fVolatile) + if x&y == y { + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + if a.underlyingType() != nil && b.underlyingType() != nil && a.isCompatibleIgnoreQualifiers(b) { + return true + } + + if a.IsIncomplete() || b.IsIncomplete() && a.Kind() == b.Kind() { + return true + } + + if a.IsIntegerType() && b.IsIntegerType() { + return true + } + } + // trc("a %T %[1]v, x %#x, b %T %[3]v, y %#x, x&y %#x", a, x, b, y, x&y) + // trc("a %+v, b%+v", a.base(), b.base()) + return false + } + return rhs.Kind() == Function && t.Elem().IsAssingmentCompatible(rhs) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *pointerType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + rhsType := rhs.Type() + if rhsType.Kind() == Function { + if t.Elem().Kind() == Void { + return true + } + + return t.Elem().IsCompatible(rhsType) + } + + // — the left operand is a pointer and the right is a null pointer constant; or + return rhs.IsZero() || t.IsAssingmentCompatible(rhsType) +} + +// IsCompatible implements Type. +func (t *pointerType) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if u.Kind() != Ptr { + return false + } + + v := u.(*pointerType) + // [0], 6.7.5.1 + // + // 2 For two pointer types to be compatible, both shall be identically + // qualified and both shall be pointers to compatible types.; + if t.typeBase.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) != v.typeBase.flags&(fAtomic|fConst|fRestrict|fVolatile|fSigned) { + return false + } + + return t.Elem().IsCompatible(v.Elem()) +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *pointerType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if u.Kind() != Ptr { + return false + } + + v := u.(*pointerType) + if t.Elem().Kind() == Void || v.Elem().Kind() == Void { + return true + } + + return t.Elem().isCompatibleIgnoreQualifiers(v.Elem()) +} + +// Alias implements Type. +func (t *pointerType) Alias() Type { return t } + +// Attributes implements Type. +func (t *pointerType) Attributes() (a []*AttributeSpecifier) { return t.elem.Attributes() } + +// Decay implements Type. +func (t *pointerType) Decay() Type { return t } + +// Elem implements Type. +func (t *pointerType) Elem() Type { return t.elem } + +// underlyingType implements Type. +func (t *pointerType) underlyingType() Type { return t } + +// String implements Type. +func (t *pointerType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// string implements Type. +func (t *pointerType) string(b *bytes.Buffer) { + if t := t.typeQualifiers; t != nil { + t.string(b) + } + b.WriteString("pointer to ") + t.Elem().string(b) +} + +type arrayType struct { + typeBase + + expr *AssignmentExpression + decay Type + elem Type + length uintptr + + vla bool +} + +// IsAssingmentCompatible implements Type. +func (t *arrayType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if rhs = rhs.Alias().Decay(); t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + if rhs.Kind() == Array { + rhs = rhs.Decay() + } + + return t.Decay().IsAssingmentCompatible(t) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *arrayType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + return t.IsAssingmentCompatible(rhs.Type()) +} + +// IsCompatible implements Type. +func (t *arrayType) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if t.vla || u.Kind() != Array { + return false + } + + v := u.(*arrayType) + // [0], 6.7.5.2 + // + // 6 For two array types to be compatible, both shall have compatible element + // types, and if both size specifiers are present, and are integer constant + // expressions, then both size specifiers shall have the same constant value. + // If the two array types are used in a context which requires them to be + // compatible, it is undefined behavior if the two size specifiers evaluate to + // unequal values. + return !t.vla && !v.vla && t.length == v.length && t.elem.IsCompatible(v.elem) +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *arrayType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + return t.IsCompatible(u) +} + +// IsCompatibleLayout implements Type. +func (t *arrayType) IsCompatibleLayout(u Type) bool { + if u = u.Alias().Decay(); t == u { + return true + } + + if t.vla || u.Kind() != Array { + return false + } + + v := u.(*arrayType) + return !t.vla && !v.vla && t.length == v.length && t.elem.IsCompatibleLayout(v.elem) +} + +// Alias implements Type. +func (t *arrayType) Alias() Type { return t } + +// IsVLA implements Type. +func (t *arrayType) IsVLA() bool { return t.vla || t.elem.Kind() == Array && t.Elem().IsVLA() } + +// String implements Type. +func (t *arrayType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// string implements Type. +func (t *arrayType) string(b *bytes.Buffer) { + b.WriteString("array of ") + if t.Len() != 0 { + fmt.Fprintf(b, "%d ", t.Len()) + } + t.Elem().string(b) +} + +// Attributes implements Type. +func (t *arrayType) Attributes() (a []*AttributeSpecifier) { return t.elem.Attributes() } + +// Decay implements Type. +func (t *arrayType) Decay() Type { return t.decay } + +// Elem implements Type. +func (t *arrayType) Elem() Type { return t.elem } + +// Len implements Type. +func (t *arrayType) Len() uintptr { return t.length } + +// LenExpr implements Type. +func (t *arrayType) LenExpr() *AssignmentExpression { + if !t.vla { + panic(internalErrorf("%s: LenExpr of non variable length array", t.Kind())) + } + + return t.expr +} + +// setLen implements Type. +func (t *arrayType) setLen(n uintptr) { + t.typeBase.flags &^= fIncomplete + t.length = n + if t.Elem() != nil { + t.size = t.length * t.Elem().Size() + } +} + +// underlyingType implements Type. +func (t *arrayType) underlyingType() Type { return t } + +type aliasType struct { + *typeBase + nm StringID + d *Declarator +} + +// HasFlexibleMember implements Type. +func (t *aliasType) HasFlexibleMember() bool { + return t.d.Type().HasFlexibleMember() +} + +// IsAssingmentCompatible implements Type. +func (t *aliasType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if t == rhs { + return true + } + + if x, ok := rhs.(*aliasType); ok && t.nm == x.nm { + return true + } + + if rhs = rhs.Alias().Decay(); t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + return t.d.Type().IsAssingmentCompatible(rhs) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *aliasType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if x, ok := rhs.Type().(*aliasType); ok && t.nm == x.nm { + return true + } + + rhsType := rhs.Type().Decay() + if t == rhsType { + return true + } + + return t.d.Type().isAssingmentCompatibleOperand(rhs) +} + +// IsCompatible implements Type. +func (t *aliasType) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if x, ok := u.(*aliasType); ok && t.nm == x.nm { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + return t.d.Type().IsCompatible(u) +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *aliasType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if x, ok := u.(*aliasType); ok && t.nm == x.nm { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + return t.d.Type().isCompatibleIgnoreQualifiers(u) +} + +// IsCompatibleLayout implements Type. +func (t *aliasType) IsCompatibleLayout(u Type) bool { + if t == nil || u == nil { + return false + } + + if x, ok := u.(*aliasType); ok && t.nm == x.nm { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + return t.d.Type().IsCompatibleLayout(u) +} + +// IsPacked implements Type. +func (t *aliasType) IsPacked() bool { + if t == nil { + return false + } + + return t.d.Type().IsPacked() +} + +// UnionCommon implements Type. +func (t *aliasType) UnionCommon() Kind { return t.d.Type().UnionCommon() } + +// IsAliasType implements Type. +func (t *aliasType) IsAliasType() bool { return true } + +// IsAggregate implements Type. +func (t *aliasType) IsAggregate() bool { return t.d.Type().IsAggregate() } + +func (t *aliasType) AliasDeclarator() *Declarator { return t.d } + +// IsTaggedType implements Type. +func (t *aliasType) IsTaggedType() bool { return false } + +// Alias implements Type. +func (t *aliasType) Alias() Type { return t.d.Type() } + +// Align implements Type. +func (t *aliasType) Align() int { return t.d.Type().Align() } + +// Attributes implements Type. +func (t *aliasType) Attributes() (a []*AttributeSpecifier) { return t.d.Type().Attributes() } + +// BitField implements Type. +func (t *aliasType) BitField() Field { return t.d.Type().BitField() } + +// EnumType implements Type. +func (t *aliasType) EnumType() Type { return t.d.Type().EnumType() } + +// Decay implements Type. +func (t *aliasType) Decay() Type { return t.d.Type().Decay() } + +// Elem implements Type. +func (t *aliasType) Elem() Type { return t.d.Type().Elem() } + +// FieldAlign implements Type. +func (t *aliasType) FieldAlign() int { return t.d.Type().FieldAlign() } + +// NumField implements Type. +func (t *aliasType) NumField() int { return t.d.Type().NumField() } + +// FieldByIndex implements Type. +func (t *aliasType) FieldByIndex(i []int) Field { return t.d.Type().FieldByIndex(i) } + +// FieldByName implements Type. +func (t *aliasType) FieldByName(s StringID) (Field, bool) { return t.d.Type().FieldByName(s) } + +// FieldByName2 implements Type. +func (t *aliasType) FieldByName2(s StringID) (Field, []int, bool) { return t.d.Type().FieldByName2(s) } + +// IsIncomplete implements Type. +func (t *aliasType) IsIncomplete() bool { return t.d.Type().IsIncomplete() } + +// IsArithmeticType implements Type. +func (t *aliasType) IsArithmeticType() bool { return t.d.Type().IsArithmeticType() } + +// IsComplexType implements Type. +func (t *aliasType) IsComplexType() bool { return t.d.Type().IsComplexType() } + +// IsComplexIntegerType implements Type. +func (t *aliasType) IsComplexIntegerType() bool { return t.d.Type().IsComplexIntegerType() } + +// IsBitFieldType implements Type. +func (t *aliasType) IsBitFieldType() bool { return t.d.Type().IsBitFieldType() } + +// IsIntegerType implements Type. +func (t *aliasType) IsIntegerType() bool { return t.d.Type().IsIntegerType() } + +// IsRealType implements Type. +func (t *aliasType) IsRealType() bool { return t.d.Type().IsRealType() } + +// IsScalarType implements Type. +func (t *aliasType) IsScalarType() bool { return t.d.Type().IsScalarType() } + +// IsVLA implements Type. +func (t *aliasType) IsVLA() bool { return t.d.Type().IsVLA() } + +// IsVariadic implements Type. +func (t *aliasType) IsVariadic() bool { return t.d.Type().IsVariadic() } + +// Kind implements Type. +func (t *aliasType) Kind() Kind { return t.d.Type().Kind() } + +// Len implements Type. +func (t *aliasType) Len() uintptr { return t.d.Type().Len() } + +// LenExpr implements Type. +func (t *aliasType) LenExpr() *AssignmentExpression { return t.d.Type().LenExpr() } + +// Parameters implements Type. +func (t *aliasType) Parameters() []*Parameter { return t.d.Type().Parameters() } + +// Result implements Type. +func (t *aliasType) Result() Type { return t.d.Type().Result() } + +// Real implements Type +func (t *aliasType) Real() Field { return t.d.Type().Real() } + +// Imag implements Type +func (t *aliasType) Imag() Field { return t.d.Type().Imag() } + +// Size implements Type. +func (t *aliasType) Size() uintptr { return t.d.Type().Size() } + +// String implements Type. +func (t *aliasType) String() string { + var a []string + if t.typeBase.IsAtomic() { + a = append(a, "atomic") + } + if t.typeBase.hasConst() { + a = append(a, "const") + } + if t.typeBase.Inline() { + a = append(a, "inline") + } + if t.typeBase.noReturn() { + a = append(a, "_NoReturn") + } + if t.typeBase.restrict() { + a = append(a, "restrict") + } + if t.typeBase.IsVolatile() { + a = append(a, "volatile") + } + a = append(a, t.nm.String()) + return strings.Join(a, " ") +} + +// Tag implements Type. +func (t *aliasType) Tag() StringID { return t.d.Type().Tag() } + +// Name implements Type. +func (t *aliasType) Name() StringID { return t.nm } + +// IsAtomic implements Type. +func (t *aliasType) IsAtomic() bool { return t.d.Type().IsAtomic() } + +// Inline implements Type. +func (t *aliasType) Inline() bool { return t.d.Type().Inline() } + +// IsSignedType implements Type. +func (t *aliasType) IsSignedType() bool { return t.d.Type().IsSignedType() } + +// noReturn implements Type. +func (t *aliasType) noReturn() bool { return t.d.Type().noReturn() } + +// restrict implements Type. +func (t *aliasType) restrict() bool { return t.d.Type().restrict() } + +// setLen implements Type. +func (t *aliasType) setLen(n uintptr) { t.d.Type().setLen(n) } + +// setKind implements Type. +func (t *aliasType) setKind(k Kind) { t.d.Type().setKind(k) } + +// string implements Type. +func (t *aliasType) string(b *bytes.Buffer) { b.WriteString(t.String()) } + +func (t *aliasType) underlyingType() Type { return t.d.Type().underlyingType() } + +// IsVolatile implements Type. +func (t *aliasType) IsVolatile() bool { return t.d.Type().IsVolatile() } + +func (t *aliasType) isVectorType() bool { return t.d.Type().isVectorType() } + +func (t *aliasType) setFnSpecs(inline, noret bool) { t.d.Type().setFnSpecs(inline, noret) } + +type field struct { + bitFieldMask uint64 // bits: 3, bitOffset: 2 -> 0x1c. Valid only when isBitField is true. + blockStart *field // First bit field of the block this bit field belongs to. + d *StructDeclarator + offset uintptr // In bytes from start of the struct. + parent Type + promote Type + typ Type + + name StringID // Can be zero. + x int + xs []int + + isBitField bool + isFlexible bool // https://en.wikipedia.org/wiki/Flexible_array_member + inUnion bool // directly or indirectly + + bitFieldOffset byte // In bits from bit 0 within the field. Valid only when isBitField is true. + bitFieldWidth byte // Width of the bit field in bits. Valid only when isBitField is true. + blockWidth byte // Total width of the bit field block this bit field belongs to. + pad byte +} + +func (f *field) BitFieldBlockFirst() Field { return f.blockStart } +func (f *field) BitFieldBlockWidth() int { return int(f.blockWidth) } +func (f *field) BitFieldOffset() int { return int(f.bitFieldOffset) } +func (f *field) BitFieldWidth() int { return int(f.bitFieldWidth) } +func (f *field) Declarator() *StructDeclarator { return f.d } +func (f *field) InUnion() bool { return f.inUnion } +func (f *field) Index() int { return f.x } +func (f *field) IsBitField() bool { return f.isBitField } +func (f *field) IsFlexible() bool { return f.isFlexible } +func (f *field) Mask() uint64 { return f.bitFieldMask } +func (f *field) Name() StringID { return f.name } +func (f *field) Offset() uintptr { return f.offset } +func (f *field) Padding() int { return int(f.pad) } // N/A for bitfields +func (f *field) Parent() Type { return f.parent } +func (f *field) Promote() Type { return f.promote } +func (f *field) Type() Type { return f.typ } +func (f *field) at(offDelta uintptr) *field { r := *f; r.offset += offDelta; return &r } + +func (f *field) string(b *bytes.Buffer) { + b.WriteString(f.name.String()) + if f.isBitField { + fmt.Fprintf(b, ":%d", f.bitFieldWidth) + } + b.WriteByte(' ') + f.typ.string(b) +} + +type fieldPath struct { + fld *field + path []int + + ambiguous bool +} + +func (f *fieldPath) String() string { + return fmt.Sprintf("%q %v %v", f.fld.name, f.path, f.ambiguous) +} + +type structType struct { + *typeBase + + attr []*AttributeSpecifier + common Kind + fields []*field + m map[StringID]*field + paths map[StringID]*fieldPath + + tag StringID + + hasFlexibleMember bool +} + +// HasFlexibleMember implements Type. +func (t *structType) HasFlexibleMember() bool { return t.hasFlexibleMember } + +// IsAssingmentCompatible implements Type. +func (t *structType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if rhs = rhs.Alias().Decay(); t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + return t.IsCompatible(rhs) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *structType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + rhsType := rhs.Type().Decay() + if t == rhsType { + return true + } + + return t.IsAssingmentCompatible(rhsType) +} + +func (t *structType) firstUnionField() Field { + for _, f := range t.fields { + if f.Name() != 0 || !f.Type().IsBitFieldType() { + return f + } + } + panic(todo("")) +} + +// IsCompatible implements Type. +func (t *structType) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t.Kind() == Union { + return t.firstUnionField().Type().IsCompatible(u) + } + + if t.IsComplexType() && u.IsArithmeticType() { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + v, ok := u.(*structType) + if !ok || t.Kind() != v.Kind() { + return false + } + + if t.tag != 0 && t.tag == v.tag { + return true + } + + if t.tag != v.tag || len(t.fields) != len(v.fields) { + return false + } + + if (t.IsIncomplete() || v.IsIncomplete()) && t.tag == v.tag { + return true + } + + for i, f1 := range t.fields { + f2 := v.fields[i] + nm := f1.Name() + if f2.Name() != nm { + return false + } + + ft1 := f1.Type() + ft2 := f2.Type() + if ft1.Size() != ft2.Size() || + f1.IsBitField() != f2.IsBitField() || + f1.BitFieldOffset() != f2.BitFieldOffset() || + f1.BitFieldWidth() != f2.BitFieldWidth() { + return false + } + + if !ft1.IsCompatible(ft2) { + return false + } + } + return true +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *structType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + return t.IsCompatible(u) +} + +// IsCompatibleLayout implements Type. +func (t *structType) IsCompatibleLayout(u Type) bool { + if u = u.Alias().Decay(); t == u { + return true + } + + v, ok := u.(*structType) + if !ok || t.Kind() != v.Kind() { + return false + } + + if t.tag != v.tag || len(t.fields) != len(v.fields) { + return false + } + + for i, f1 := range t.fields { + f2 := v.fields[i] + nm := f1.Name() + if f2.Name() != nm { + return false + } + + ft1 := f1.Type() + ft2 := f2.Type() + if ft1.Size() != ft2.Size() || + f1.IsBitField() != f2.IsBitField() || + f1.BitFieldOffset() != f2.BitFieldOffset() || + f1.BitFieldWidth() != f2.BitFieldWidth() { + return false + } + + if ft1.IsCompatible(ft2) { + return false + } + } + return true +} + +// UnionCommon implements Type. +func (t *structType) UnionCommon() Kind { + if t.Kind() != Union { + panic(internalErrorf("%s: UnionCommon of invalid type", t.Kind())) + } + + return t.common +} + +// Alias implements Type. +func (t *structType) Alias() Type { return t } + +// Tag implements Type. +func (t *structType) Tag() StringID { return t.tag } + +func (t *structType) check(ctx *context, n Node) *structType { + if t == nil { + return nil + } + + // Reject ambiguous names. + for _, f := range t.fields { + f.parent = t + if f.Name() != 0 { + continue + } + + switch x := f.Type().(type) { + case *structType: + for _, f2 := range x.fields { + nm := f2.Name() + if nm == 0 { + continue + } + + if _, ok := t.m[nm]; ok { + ctx.errNode(n, "ambiguous field name %q", nm) + } + } + default: + //TODO report err + } + } + + return ctx.cfg.ABI.layout(ctx, n, t) +} + +// Real implements Type +func (t *structType) Real() Field { + if !complexTypes[t.Kind()] { + panic(internalErrorf("%s: Real of invalid type", t.Kind())) + } + + f, ok := t.FieldByName(idReal) + if !ok { + panic(internalError()) + } + + return f +} + +// Imag implements Type +func (t *structType) Imag() Field { + if !complexTypes[t.Kind()] { + panic(internalErrorf("%s: Real of invalid type", t.Kind())) + } + + f, ok := t.FieldByName(idImag) + if !ok { + panic(internalError()) + } + + return f +} + +// Decay implements Type. +func (t *structType) Decay() Type { return t } + +func (t *structType) underlyingType() Type { return t } + +// String implements Type. +func (t *structType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// Name implements Type. +func (t *structType) Name() StringID { return t.tag } + +// string implements Type. +func (t *structType) string(b *bytes.Buffer) { + switch { + case complexTypes[t.Kind()]: + b.WriteString(t.Kind().String()) + return + default: + b.WriteString(t.Kind().String()) + } + b.WriteByte(' ') + if t.tag != 0 { + b.WriteString(t.tag.String()) + b.WriteByte(' ') + } + b.WriteByte('{') + for _, v := range t.fields { + v.string(b) + b.WriteString("; ") + } + b.WriteByte('}') +} + +// FieldByIndex implements Type. +func (t *structType) FieldByIndex(i []int) Field { + if len(i) > 1 { + panic("TODO") + } + + return t.fields[i[0]] +} + +// FieldByName implements Type. +func (t *structType) FieldByName(name StringID) (Field, bool) { + if f := t.m[name]; f != nil { + return f, true + } + + if t.paths == nil { + t.paths = map[StringID]*fieldPath{} + t.computePaths(0, t.paths, nil) + } + nfo := t.paths[name] + if nfo == nil || nfo.ambiguous { + return nil, false + } + + return nfo.fld, true +} + +// FieldByName2 implements Type. +func (t *structType) FieldByName2(name StringID) (Field, []int, bool) { + if f := t.m[name]; f != nil { + return f, f.xs, true + } + + if t.paths == nil { + t.paths = map[StringID]*fieldPath{} + t.computePaths(0, t.paths, nil) + } + nfo := t.paths[name] + if nfo == nil || nfo.ambiguous { + return nil, nil, false + } + + return nfo.fld, nfo.path, true +} + +func (t *structType) computePaths(off uintptr, paths map[StringID]*fieldPath, path []int) { + path = append(path, 0) + for i, f := range t.fields { + nm := f.Name() + path[len(path)-1] = i + if nm != 0 { + switch ex := paths[nm]; { + case ex != nil: + switch { + case len(path) < len(ex.path): + ex.fld = f.at(off) + ex.path = append([]int(nil), path...) + ex.ambiguous = false + case len(path) == len(ex.path) && (off+f.Offset() != ex.fld.Offset() || f.Type().Size() != ex.fld.Type().Size()): + ex.ambiguous = true + } + default: + paths[nm] = &fieldPath{fld: f.at(off), path: append([]int(nil), path...)} + } + } + if x, ok := f.Type().underlyingType().(*structType); ok { + x.computePaths(off+f.Offset(), paths, path) + } + } +} + +// NumField implements Type. +func (t *structType) NumField() int { return len(t.fields) } + +type taggedType struct { + *typeBase + resolutionScope Scope + typ Type + + tag StringID +} + +// IsPacked implements Type. +func (t *taggedType) IsPacked() bool { + if t == nil { + return false + } + + return t.underlyingType().IsPacked() +} + +// HasFlexibleMember implements Type. +func (t *taggedType) HasFlexibleMember() bool { + return t.typ.HasFlexibleMember() +} + +// IsAssingmentCompatible implements Type. +func (t *taggedType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if t == rhs { + return true + } + + if t.Kind() == rhs.Kind() && t.tag != 0 && t.tag == rhs.Tag() { + return true + } + + if rhs = rhs.Alias().Decay(); t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + return t.typ.IsAssingmentCompatible(rhs) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *taggedType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + rhsType := rhs.Type().Decay() + if t == rhsType { + return true + } + + if t.Kind() == rhsType.Kind() && t.tag != 0 && t.tag == rhsType.Tag() { + return true + } + + return t.IsAssingmentCompatible(rhsType) +} + +// IsCompatible implements Type. +func (t *taggedType) IsCompatible(u Type) (r bool) { + defer func() { + // if !r { + // trc("TRACE %v <- %v: %v (%s)", t, u0, r, origin(2)) //TODO- + // } + }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if t.Kind() == u.Kind() && t.tag != 0 && t.tag == u.Tag() { + return true + } + + return t.typ.IsCompatible(u) +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *taggedType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if t.Kind() == u.Kind() && t.tag != 0 && t.tag == u.Tag() { + return true + } + + return t.typ.isCompatibleIgnoreQualifiers(u) +} + +// IsCompatibleLayout implements Type. +func (t *taggedType) IsCompatibleLayout(u Type) bool { + if u = u.Alias().Decay(); t == u { + return true + } + + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if t.Kind() == u.Kind() && t.tag != 0 && t.tag == u.Tag() { + return true + } + + return t.typ.IsCompatibleLayout(u) +} + +// UnionCommon implements Type. +func (t *taggedType) UnionCommon() Kind { return t.typ.UnionCommon() } + +// IsTaggedType implements Type. +func (t *taggedType) IsTaggedType() bool { return true } + +// Tag implements Type. +func (t *taggedType) Tag() StringID { return t.tag } + +// Alias implements Type. +func (t *taggedType) Alias() Type { return t.underlyingType() } + +// Decay implements Type. +func (t *taggedType) Decay() Type { return t } + +// IsIncomplete implements Type. +func (t *taggedType) IsIncomplete() bool { + u := t.underlyingType() + return u == noType || u.IsIncomplete() +} + +// String implements Type. +func (t *taggedType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// Name implements Type. +func (t *taggedType) Name() StringID { return t.tag } + +// NumField implements Type. +func (t *taggedType) NumField() int { return t.underlyingType().NumField() } + +// FieldByIndex implements Type. +func (t *taggedType) FieldByIndex(i []int) Field { return t.underlyingType().FieldByIndex(i) } + +// FieldByName implements Type. +func (t *taggedType) FieldByName(s StringID) (Field, bool) { return t.underlyingType().FieldByName(s) } + +// FieldByName2 implements Type. +func (t *taggedType) FieldByName2(s StringID) (Field, []int, bool) { + return t.underlyingType().FieldByName2(s) +} + +// IsSignedType implements Type. +func (t *taggedType) IsSignedType() bool { return t.underlyingType().IsSignedType() } + +// EnumType implements Type. +func (t *taggedType) EnumType() Type { return t.underlyingType() } + +// string implements Type. +func (t *taggedType) string(b *bytes.Buffer) { + t.typeBase.string(b) + b.WriteByte(' ') + b.WriteString(t.tag.String()) +} + +func (t *taggedType) underlyingType() Type { + if t.typ != nil { + return t.typ + } + + k := t.Kind() + for s := t.resolutionScope; s != nil; s = s.Parent() { + for _, v := range s[t.tag] { + switch x := v.(type) { + case *Declarator, *StructDeclarator, *LabeledStatement: + // nop + case *EnumSpecifier: + if k == Enum && x.Case == EnumSpecifierDef { + t.typ = x.Type() + return t.typ.underlyingType() + } + case *StructOrUnionSpecifier: + if x.typ == nil { + break + } + + switch k { + case Struct: + if typ := x.Type(); typ.Kind() == Struct { + t.typ = typ + return typ.underlyingType() + } + case Union: + if typ := x.Type(); typ.Kind() == Union { + t.typ = typ + return typ.underlyingType() + } + } + default: + panic(todo("internal error: %T", x)) + } + } + } + t.typ = noType + return noType +} + +// Size implements Type. +func (t *taggedType) Size() (r uintptr) { + return t.underlyingType().Size() +} + +// Align implements Type. +func (t *taggedType) Align() int { return t.underlyingType().Align() } + +// FieldAlign implements Type. +func (t *taggedType) FieldAlign() int { return t.underlyingType().FieldAlign() } + +type functionType struct { + typeBase + params []*Parameter + paramList []StringID + + result Type + + variadic bool +} + +// IsAssingmentCompatible implements Type. +func (t *functionType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if rhs = rhs.Alias().Decay(); t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + if rhs.Kind() != Function { + return false + } + + v := rhs.(*functionType) + if t.params != nil && v.params != nil || t.variadic != v.variadic { + if len(t.params) != len(v.params) { + return false + } + + for i, x := range t.params { + if !x.Type().IsAssingmentCompatible(v.params[i].Type()) { + return false + } + } + } + return t.result.IsAssingmentCompatible(v.result) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *functionType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + rhsType := rhs.Type().Decay() + if t == rhsType { + return true + } + + return t.IsAssingmentCompatible(rhsType) +} + +// IsCompatible implements Type. +func (t *functionType) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if u = u.Alias().Decay(); t == u { + return true + } + + if u.Kind() != Function { + return false + } + + v := u.(*functionType) + // [0], 6.7.5.3 + // + // 15 For two function types to be compatible, both shall specify compatible + // return types. + // + // Moreover, the parameter type lists, if both are present, shall agree in the + // number of parameters and in use of the ellipsis terminator; corresponding + // parameters shall have compatible types. If one type has a parameter type + // list and the other type is specified by a function declarator that is not + // part of a function definition and that contains an empty identifier list, + // the parameter list shall not have an ellipsis terminator and the type of + // each parameter shall be compatible with the type that results from the + // application of the default argument promotions. If one type has a parameter + // type list and the other type is specified by a function definition that + // contains a (possibly empty) identifier list, both shall agree in the number + // of parameters, and the type of each prototype parameter shall be compatible + // with the type that results from the application of the default argument + // promotions to the type of the corresponding identifier. (In the + // determination of type compatibility and of a composite type, each parameter + // declared with function or array type is taken as having the adjusted type + // and each parameter declared with qualified type is taken as having the + // unqualified version of its declared type.) + if t.params != nil && v.params != nil || t.variadic != v.variadic { + if len(t.params) != len(v.params) { + return false + } + + for i, x := range t.params { + if !x.Type().IsCompatible(v.params[i].Type()) { + return false + } + } + } + return t.result.IsCompatible(v.result) +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *functionType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + return t.IsCompatible(u) +} + +// Alias implements Type. +func (t *functionType) Alias() Type { return t } + +// Decay implements Type. +func (t *functionType) Decay() Type { return t } + +// String implements Type. +func (t *functionType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// string implements Type. +func (t *functionType) string(b *bytes.Buffer) { + b.WriteString("function(") + for i, v := range t.params { + v.Type().string(b) + if i < len(t.params)-1 { + b.WriteString(", ") + } + } + if t.variadic { + b.WriteString(", ...") + } + b.WriteString(")") + if t.result != nil && t.result.Kind() != Void { + b.WriteString(" returning ") + t.result.string(b) + } +} + +// Parameters implements Type. +func (t *functionType) Parameters() []*Parameter { return t.params } + +// Result implements Type. +func (t *functionType) Result() Type { return t.result } + +// IsVariadic implements Type. +func (t *functionType) IsVariadic() bool { return t.variadic } + +type bitFieldType struct { + Type + field *field +} + +// Alias implements Type. +func (t *bitFieldType) Alias() Type { return t } + +// IsBitFieldType implements Type. +func (t *bitFieldType) IsBitFieldType() bool { return true } + +// BitField implements Type. +func (t *bitFieldType) BitField() Field { return t.field } + +type vectorType struct { + typeBase + + elem Type + length uintptr +} + +// IsAssingmentCompatible implements Type. +func (t *vectorType) IsAssingmentCompatible(rhs Type) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v\n%s", t, rhs0, debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + if t == rhs { + return true + } + + // [0], 6.5.16.1 Simple assignment + // + // 1 One of the following shall hold: + // + // — the left operand has qualified or unqualified arithmetic type and the + // right has arithmetic type; + // + // — the left operand has a qualified or unqualified version of a structure or + // union type compatible with the type of the right; + // + // — both operands are pointers to qualified or unqualified versions of + // compatible types, and the type pointed to by the left has all the qualifiers + // of the type pointed to by the right; + // + // — one operand is a pointer to an object or incomplete type and the other is + // a pointer to a qualified or unqualified version of void, and the type + // pointed to by the left has all the qualifiers of the type pointed to by the + // right; + // + // — the left operand is a pointer and the right is a null pointer constant; or + // + // — the left operand has type _Bool and the right is a pointer. + return t.IsCompatible(rhs) +} + +// isAssingmentCompatibleOperand implements Type. +func (t *vectorType) isAssingmentCompatibleOperand(rhs Operand) (r bool) { + // defer func() { + // rhs0 := rhs + // if !r { + // trc("TRACE %v <- %v %v\n%s", t, rhs0.Value(), rhs0.Type(), debug.Stack()) //TODO- + // } + // }() + if t == nil || rhs == nil { + return false + } + + rhsType := rhs.Type() + if t == rhsType { + return true + } + + return t.IsAssingmentCompatible(rhsType) +} + +// IsCompatible implements Type. +func (t *vectorType) IsCompatible(u Type) (r bool) { + // defer func() { + // u0 := u + // if !r { + // trc("TRACE %v <- %v\n%s", t, u0, debug.Stack()) //TODO- + // } + // }() + if t == nil || u == nil { + return false + } + + if t == u { + return true + } + + if t == u { + return true + } + + if u.Kind() != Vector { + return false + } + + v := u.(*vectorType) + return t.length == v.length && t.elem.IsCompatible(v.elem) +} + +// isCompatibleIgnoreQualifiers implements Type. +func (t *vectorType) isCompatibleIgnoreQualifiers(u Type) (r bool) { + return t.IsCompatible(u) +} + +// IsCompatibleLayout implements Type. +func (t *vectorType) IsCompatibleLayout(u Type) bool { + if u = u.Alias().Decay(); t == u { + return true + } + + if u.Kind() != Vector { + return false + } + + v := u.(*vectorType) + return t.length == v.length && t.elem.IsCompatibleLayout(v.elem) +} + +// Alias implements Type. +func (t *vectorType) Alias() Type { return t } + +// IsVLA implements Type. +func (t *vectorType) IsVLA() bool { return false } + +// String implements Type. +func (t *vectorType) String() string { + b := bytesBufferPool.Get().(*bytes.Buffer) + defer func() { b.Reset(); bytesBufferPool.Put(b) }() + t.string(b) + return strings.TrimSpace(b.String()) +} + +// string implements Type. +func (t *vectorType) string(b *bytes.Buffer) { + fmt.Fprintf(b, "vector of %d ", t.Len()) + t.Elem().string(b) +} + +// Attributes implements Type. +func (t *vectorType) Attributes() (a []*AttributeSpecifier) { return t.elem.Attributes() } + +// Elem implements Type. +func (t *vectorType) Elem() Type { return t.elem } + +// Len implements Type. +func (t *vectorType) Len() uintptr { return t.length } + +// LenExpr implements Type. +func (t *vectorType) LenExpr() *AssignmentExpression { + panic(internalErrorf("%s: LenExpr of non variable length array", t.Kind())) +} + +// setLen implements Type. +func (t *vectorType) setLen(n uintptr) { + panic("internal error") +} + +// underlyingType implements Type. +func (t *vectorType) underlyingType() Type { return t } + +func isCharType(t Type) bool { + switch t.Kind() { + case Char, SChar, UChar, Int8, UInt8: + return true + } + + return false +} + +func isWCharType(t Type) bool { + switch { + case t.IsAliasType(): + id := t.AliasDeclarator().Name() + return id == idWcharT || id == idWinWchar + default: + return false + } +} + +// Struct layout describes storage details of a struct/union type. +type StructLayout struct { + Offsets []uintptr // In field order. + OffsetToFields map[uintptr][]Field + PaddingsBefore map[Field]int + PaddingAfter int + t Type + + NeedExplicitAlign bool +} + +// NewStructLayout returns a newly created StructLayout for t, or nil if t is +// not a struct/union type. +func NewStructLayout(t Type) *StructLayout { + switch t.Kind() { + case Struct, Union: + // ok + default: + return nil + } + + nf := t.NumField() + flds := map[uintptr][]Field{} + var maxAlign int + for idx := []int{0}; idx[0] < nf; idx[0]++ { + f := t.FieldByIndex(idx) + if f.IsBitField() && f.BitFieldWidth() == 0 { + continue + } + + if a := f.Type().Align(); !f.IsBitField() && a > maxAlign { + maxAlign = a + } + off := f.Offset() + flds[off] = append(flds[off], f) + } + var offs []uintptr + for k := range flds { + offs = append(offs, k) + } + sort.Slice(offs, func(i, j int) bool { return offs[i] < offs[j] }) + var pads map[Field]int + var pos uintptr + var forceAlign bool + for _, off := range offs { + f := flds[off][0] + ft := f.Type() + //trc("%q off %d pos %d %v %v %v", f.Name(), off, pos, ft, ft.Kind(), ft.IsIncomplete()) + switch { + case ft.IsBitFieldType(): + if p := int(off - pos); p != 0 { + if pads == nil { + pads = map[Field]int{} + } + pads[f] = p + pos = off + } + pos += uintptr(f.BitFieldBlockWidth()) >> 3 + default: + var sz uintptr + switch { + case ft.Kind() != Array || ft.Len() != 0: + sz = ft.Size() + default: + forceAlign = true + } + if p := int(off - pos); p != 0 { + if pads == nil { + pads = map[Field]int{} + } + pads[f] = p + pos = off + } + pos += sz + } + } + return &StructLayout{ + NeedExplicitAlign: forceAlign || maxAlign < t.Align(), + OffsetToFields: flds, + Offsets: offs, + PaddingAfter: int(t.Size() - pos), + PaddingsBefore: pads, + t: t, + } +} + +func (x *StructLayout) String() string { + t := x.t + nf := t.NumField() + var a []string + w := 0 + for i := 0; i < nf; i++ { + if n := len(t.FieldByIndex([]int{i}).Name().String()); n > w { + w = n + } + } + for i := 0; i < nf; i++ { + f := t.FieldByIndex([]int{i}) + var bf StringID + if f.IsBitField() { + if bfbf := f.(*field).blockStart; bfbf != nil { + bf = bfbf.Name() + } + } + a = append(a, fmt.Sprintf("%3d: %*q: BitFieldOffset %3v, BitFieldWidth %3v, IsBitField %5v, Mask: %#016x, off: %3v, pad %2v, BitFieldBlockWidth: %2d, BitFieldBlockFirst: %s, %v", + i, w+2, f.Name(), f.BitFieldOffset(), f.BitFieldWidth(), + f.IsBitField(), f.Mask(), f.Offset(), f.Padding(), + f.BitFieldBlockWidth(), bf, f.Type(), + )) + } + var b strings.Builder + fmt.Fprintf(&b, "%v\n%s\n----\n", t, strings.Join(a, "\n")) + fmt.Fprintf(&b, "size: %v\n", t.Size()) + fmt.Fprintf(&b, "offs: %v\n", x.Offsets) + a = a[:0] + for k, v := range x.OffsetToFields { + var b []string + for _, w := range v { + b = append(b, fmt.Sprintf("%q padBefore: %d ", w.Name(), x.PaddingsBefore[w])) + } + a = append(a, fmt.Sprintf("%4d %s", k, b)) + } + sort.Strings(a) + for _, v := range a { + fmt.Fprintf(&b, "%s\n", v) + } + fmt.Fprintf(&b, "padAfter: %v\n", x.PaddingAfter) + for i := 0; i < nf; i++ { + f := t.FieldByIndex([]int{i}) + if x, ok := f.Type().(*structType); ok { + s := dumpLayout(x) + a := strings.Split(s, "\n") + fmt.Fprintf(&b, "====\n") + for _, v := range a { + fmt.Fprintf(&b, "%s\n", v) + } + } + } + return b.String() +} + +func dumpLayout(t Type) string { + switch t.Kind() { + case Struct, Union: + // ok + default: + return t.String() + } + + return NewStructLayout(t).String() +} diff --git a/vendor/modernc.org/cc/v3/unconvert.sh b/vendor/modernc.org/cc/v3/unconvert.sh new file mode 100644 index 00000000..af3b87f8 --- /dev/null +++ b/vendor/modernc.org/cc/v3/unconvert.sh @@ -0,0 +1,4 @@ +until unconvert -fastmath . &> /dev/null +do + unconvert -fastmath -apply . &> /dev/null +done |