gotosocial/vendor/modernc.org/cc/v3/parser.go
tobi 07727753b9
[feature] Clean up/uncache remote media (#407)
* Add whereNotEmptyAndNotNull

* Add GetRemoteOlderThanDays

* Add GetRemoteOlderThanDays

* Add PruneRemote to Manager interface

* Start implementing PruneRemote

* add new attachment + status to tests

* fix up and test GetRemoteOlderThan

* fix bad import

* PruneRemote: return number pruned

* add Cached column to mediaattachment

* update + test pruneRemote

* update mediaTest

* use Cached column

* upstep bun to latest version

* embed structs in mediaAttachment

* migrate mediaAttachment to new format

* don't default cached to true

* select only remote media

* update db dependencies

* step bun back to last working version

* update pruneRemote to use Cached field

* fix storage path of test attachments

* add recache logic to manager

* fix trimmed aspect ratio

* test prune and recache

* return errwithcode

* tidy up different paths for emoji vs attachment

* fix incorrect thumbnail type being stored

* expose TransportController to media processor

* implement tee-ing recached content

* add thoughts of dog to test fedi attachments

* test get remote files

* add comment on PruneRemote

* add postData cleanup to recache

* test thumbnail fetching

* add incredible diagram

* go mod tidy

* buffer pipes for recache streaming

* test for client stops reading after 1kb

* add media-remote-cache-days to config

* add cron package

* wrap logrus so it's available to cron

* start and stop cron jobs gracefully
2022-03-07 11:08:26 +01:00

4292 lines
119 KiB
Go

// 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
}