mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-23 20:26:39 +00:00
4279 lines
119 KiB
Go
4279 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("__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() == '*' {
|
||
|
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
|
||
|
func (p *parser) pointer() (r *Pointer) {
|
||
|
if p.rune() != '*' {
|
||
|
p.err("expected *")
|
||
|
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
|
||
|
if p.rune() == '*' {
|
||
|
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() == '*' {
|
||
|
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
|
||
|
}
|