+ }
+ }
+}
+
+static initializer_t *parse_sub_initializer(type_t *type,
+ expression_t *expression,
+ type_t *expression_type)
+{
+ if(is_type_scalar(type)) {
+ /* there might be extra {} hierarchies */
+ if(token.type == '{') {
+ next_token();
+ if(!had_initializer_brace_warning) {
+ warningf(HERE, "braces around scalar initializer");
+ had_initializer_brace_warning = true;
+ }
+ initializer_t *result = parse_sub_initializer(type, NULL, NULL);
+ if(token.type == ',') {
+ next_token();
+ /* TODO: warn about excessive elements */
+ }
+ expect_block('}');
+ return result;
+ }
+
+ if(expression == NULL) {
+ expression = parse_assignment_expression();
+ }
+ return initializer_from_expression(type, expression);
+ }
+
+ /* does the expression match the currently looked at object to initialize */
+ if(expression != NULL) {
+ initializer_t *result = initializer_from_expression(type, expression);
+ if(result != NULL)
+ return result;
+ }
+
+ bool read_paren = false;
+ if(token.type == '{') {
+ next_token();
+ read_paren = true;
+ }
+
+ /* descend into subtype */
+ initializer_t *result = NULL;
+ initializer_t **elems;
+ if(is_type_array(type)) {
+ array_type_t *array_type = &type->array;
+ type_t *element_type = array_type->element_type;
+ element_type = skip_typeref(element_type);
+
+ if(token.type == '.') {
+ errorf(HERE,
+ "compound designator in initializer for array type '%T'",
+ type);
+ skip_designator();
+ }
+
+ initializer_t *sub;
+ had_initializer_brace_warning = false;
+ if(expression == NULL) {
+ sub = parse_sub_initializer_elem(element_type);
+ } else {
+ sub = parse_sub_initializer(element_type, expression,
+ expression_type);
+ }
+
+ /* didn't match the subtypes -> try the parent type */
+ if(sub == NULL) {
+ assert(!read_paren);
+ return NULL;
+ }
+
+ elems = NEW_ARR_F(initializer_t*, 0);
+ ARR_APP1(initializer_t*, elems, sub);
+
+ while(true) {
+ if(token.type == '}')
+ break;
+ expect_block(',');
+ if(token.type == '}')
+ break;
+
+ sub = parse_sub_initializer_elem(element_type);
+ if(sub == NULL) {
+ /* TODO error, do nicer cleanup */
+ errorf(HERE, "member initializer didn't match");
+ DEL_ARR_F(elems);
+ return NULL;
+ }
+ ARR_APP1(initializer_t*, elems, sub);
+ }
+ } else {
+ assert(is_type_compound(type));
+ compound_type_t *compound_type = &type->compound;
+ context_t *context = &compound_type->declaration->context;
+
+ if(token.type == '[') {
+ errorf(HERE,
+ "array designator in initializer for compound type '%T'",
+ type);
+ skip_designator();
+ }
+
+ declaration_t *first = context->declarations;
+ if(first == NULL)
+ return NULL;
+ type_t *first_type = first->type;
+ first_type = skip_typeref(first_type);
+
+ initializer_t *sub;
+ had_initializer_brace_warning = false;
+ if(expression == NULL) {
+ sub = parse_sub_initializer_elem(first_type);
+ } else {
+ sub = parse_sub_initializer(first_type, expression,expression_type);
+ }
+
+ /* didn't match the subtypes -> try our parent type */
+ if(sub == NULL) {
+ assert(!read_paren);
+ return NULL;
+ }
+
+ elems = NEW_ARR_F(initializer_t*, 0);
+ ARR_APP1(initializer_t*, elems, sub);
+
+ declaration_t *iter = first->next;
+ for( ; iter != NULL; iter = iter->next) {
+ if(iter->symbol == NULL)
+ continue;
+ if(iter->namespc != NAMESPACE_NORMAL)
+ continue;
+
+ if(token.type == '}')
+ break;
+ expect_block(',');
+ if(token.type == '}')
+ break;
+
+ type_t *iter_type = iter->type;
+ iter_type = skip_typeref(iter_type);
+
+ sub = parse_sub_initializer_elem(iter_type);
+ if(sub == NULL) {
+ /* TODO error, do nicer cleanup */
+ errorf(HERE, "member initializer didn't match");
+ DEL_ARR_F(elems);
+ return NULL;
+ }
+ ARR_APP1(initializer_t*, elems, sub);
+ }
+ }
+
+ int len = ARR_LEN(elems);
+ size_t elems_size = sizeof(initializer_t*) * len;
+
+ initializer_list_t *init = allocate_ast_zero(sizeof(init[0]) + elems_size);
+
+ init->initializer.kind = INITIALIZER_LIST;
+ init->len = len;
+ memcpy(init->initializers, elems, elems_size);
+ DEL_ARR_F(elems);
+
+ result = (initializer_t*) init;
+
+ if(read_paren) {
+ if(token.type == ',')
+ next_token();
+ expect('}');
+ }
+ return result;
+}
+
+static initializer_t *parse_initializer(type_t *type)
+{
+ initializer_t *result;
+
+ type = skip_typeref(type);
+
+ if(token.type != '{') {
+ expression_t *expression = parse_assignment_expression();
+ initializer_t *initializer = initializer_from_expression(type, expression);
+ if(initializer == NULL) {
+ errorf(HERE, "initializer expression '%E', type '%T' is incompatible with type '%T'", expression, expression->base.datatype, type);
+ }
+ return initializer;
+ }
+
+ if(is_type_scalar(type)) {
+ /* § 6.7.8.11 */
+ eat('{');
+
+ expression_t *expression = parse_assignment_expression();
+ result = initializer_from_expression(type, expression);
+
+ if(token.type == ',')
+ next_token();
+
+ expect('}');
+ return result;
+ } else {
+ result = parse_sub_initializer(type, NULL, NULL);
+ }
+
+ return result;
+}
+
+static declaration_t *append_declaration(declaration_t *declaration);
+
+static declaration_t *parse_compound_type_specifier(bool is_struct)
+{
+ if(is_struct) {
+ eat(T_struct);
+ } else {
+ eat(T_union);
+ }
+
+ symbol_t *symbol = NULL;
+ declaration_t *declaration = NULL;
+
+ if (token.type == T___attribute__) {
+ /* TODO */
+ parse_attributes();
+ }
+
+ if(token.type == T_IDENTIFIER) {
+ symbol = token.v.symbol;
+ next_token();
+
+ if(is_struct) {
+ declaration = get_declaration(symbol, NAMESPACE_STRUCT);
+ } else {
+ declaration = get_declaration(symbol, NAMESPACE_UNION);
+ }
+ } else if(token.type != '{') {
+ if(is_struct) {
+ parse_error_expected("while parsing struct type specifier",
+ T_IDENTIFIER, '{', 0);
+ } else {
+ parse_error_expected("while parsing union type specifier",
+ T_IDENTIFIER, '{', 0);
+ }
+
+ return NULL;
+ }
+
+ if(declaration == NULL) {
+ declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ if(is_struct) {
+ declaration->namespc = NAMESPACE_STRUCT;
+ } else {
+ declaration->namespc = NAMESPACE_UNION;
+ }
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_context = context;
+ if (symbol != NULL) {
+ environment_push(declaration);
+ }
+ append_declaration(declaration);
+ }
+
+ if(token.type == '{') {
+ if(declaration->init.is_defined) {
+ assert(symbol != NULL);
+ errorf(HERE, "multiple definition of '%s %Y'",
+ is_struct ? "struct" : "union", symbol);
+ declaration->context.declarations = NULL;
+ }
+ declaration->init.is_defined = true;
+
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ parse_compound_type_entries();
+ parse_attributes();
+
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+ }
+
+ return declaration;
+}
+
+static void parse_enum_entries(enum_type_t *const enum_type)
+{
+ eat('{');
+
+ if(token.type == '}') {
+ next_token();
+ errorf(HERE, "empty enum not allowed");
+ return;
+ }
+
+ do {
+ declaration_t *entry = allocate_ast_zero(sizeof(entry[0]));
+
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing enum entry", T_IDENTIFIER, 0);
+ eat_block();
+ return;
+ }
+ entry->storage_class = STORAGE_CLASS_ENUM_ENTRY;
+ entry->type = (type_t*) enum_type;
+ entry->symbol = token.v.symbol;
+ entry->source_position = token.source_position;
+ next_token();
+
+ if(token.type == '=') {
+ next_token();
+ entry->init.enum_value = parse_constant_expression();
+
+ /* TODO semantic */
+ }
+
+ record_declaration(entry);
+
+ if(token.type != ',')
+ break;
+ next_token();
+ } while(token.type != '}');
+
+ expect_void('}');
+}
+
+static type_t *parse_enum_specifier(void)
+{
+ eat(T_enum);
+
+ declaration_t *declaration;
+ symbol_t *symbol;
+
+ if(token.type == T_IDENTIFIER) {
+ symbol = token.v.symbol;
+ next_token();
+
+ declaration = get_declaration(symbol, NAMESPACE_ENUM);
+ } else if(token.type != '{') {
+ parse_error_expected("while parsing enum type specifier",
+ T_IDENTIFIER, '{', 0);
+ return NULL;
+ } else {
+ declaration = NULL;
+ symbol = NULL;
+ }
+
+ if(declaration == NULL) {
+ declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->namespc = NAMESPACE_ENUM;
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_context = context;
+ }
+
+ type_t *const type = allocate_type_zero(TYPE_ENUM);
+ type->enumt.declaration = declaration;
+
+ if(token.type == '{') {
+ if(declaration->init.is_defined) {
+ errorf(HERE, "multiple definitions of enum %Y", symbol);
+ }
+ if (symbol != NULL) {
+ environment_push(declaration);
+ }
+ append_declaration(declaration);
+ declaration->init.is_defined = 1;
+
+ parse_enum_entries(&type->enumt);
+ parse_attributes();
+ }
+
+ return type;
+}
+
+/**
+ * if a symbol is a typedef to another type, return true
+ */
+static bool is_typedef_symbol(symbol_t *symbol)
+{
+ const declaration_t *const declaration =
+ get_declaration(symbol, NAMESPACE_NORMAL);
+ return
+ declaration != NULL &&
+ declaration->storage_class == STORAGE_CLASS_TYPEDEF;
+}
+
+static type_t *parse_typeof(void)
+{
+ eat(T___typeof__);
+
+ type_t *type;
+
+ expect('(');
+
+ expression_t *expression = NULL;
+
+restart:
+ switch(token.type) {
+ case T___extension__:
+ /* this can be a prefix to a typename or an expression */
+ /* we simply eat it now. */
+ do {
+ next_token();
+ } while(token.type == T___extension__);
+ goto restart;
+
+ case T_IDENTIFIER:
+ if(is_typedef_symbol(token.v.symbol)) {
+ type = parse_typename();
+ } else {
+ expression = parse_expression();
+ type = expression->base.datatype;
+ }
+ break;
+
+ TYPENAME_START
+ type = parse_typename();
+ break;
+
+ default:
+ expression = parse_expression();
+ type = expression->base.datatype;
+ break;
+ }
+
+ expect(')');
+
+ type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF);
+ typeof_type->typeoft.expression = expression;
+ typeof_type->typeoft.typeof_type = type;
+
+ return typeof_type;
+}
+
+typedef enum {
+ SPECIFIER_SIGNED = 1 << 0,
+ SPECIFIER_UNSIGNED = 1 << 1,
+ SPECIFIER_LONG = 1 << 2,
+ SPECIFIER_INT = 1 << 3,
+ SPECIFIER_DOUBLE = 1 << 4,
+ SPECIFIER_CHAR = 1 << 5,
+ SPECIFIER_SHORT = 1 << 6,
+ SPECIFIER_LONG_LONG = 1 << 7,
+ SPECIFIER_FLOAT = 1 << 8,
+ SPECIFIER_BOOL = 1 << 9,
+ SPECIFIER_VOID = 1 << 10,
+#ifdef PROVIDE_COMPLEX
+ SPECIFIER_COMPLEX = 1 << 11,
+ SPECIFIER_IMAGINARY = 1 << 12,
+#endif
+} specifiers_t;
+
+static type_t *create_builtin_type(symbol_t *const symbol,
+ type_t *const real_type)
+{
+ type_t *type = allocate_type_zero(TYPE_BUILTIN);
+ type->builtin.symbol = symbol;
+ type->builtin.real_type = real_type;
+
+ type_t *result = typehash_insert(type);
+ if (type != result) {
+ free_type(type);
+ }
+
+ return result;
+}
+
+static type_t *get_typedef_type(symbol_t *symbol)
+{
+ declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL);
+ if(declaration == NULL
+ || declaration->storage_class != STORAGE_CLASS_TYPEDEF)
+ return NULL;
+
+ type_t *type = allocate_type_zero(TYPE_TYPEDEF);
+ type->typedeft.declaration = declaration;
+
+ return type;
+}
+
+static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
+{
+ type_t *type = NULL;
+ unsigned type_qualifiers = 0;
+ unsigned type_specifiers = 0;
+ int newtype = 0;
+
+ specifiers->source_position = token.source_position;
+
+ while(true) {
+ switch(token.type) {
+
+ /* storage class */
+#define MATCH_STORAGE_CLASS(token, class) \
+ case token: \
+ if(specifiers->storage_class != STORAGE_CLASS_NONE) { \
+ errorf(HERE, "multiple storage classes in declaration specifiers"); \
+ } \
+ specifiers->storage_class = class; \
+ next_token(); \
+ break;
+
+ MATCH_STORAGE_CLASS(T_typedef, STORAGE_CLASS_TYPEDEF)
+ MATCH_STORAGE_CLASS(T_extern, STORAGE_CLASS_EXTERN)
+ MATCH_STORAGE_CLASS(T_static, STORAGE_CLASS_STATIC)
+ MATCH_STORAGE_CLASS(T_auto, STORAGE_CLASS_AUTO)
+ MATCH_STORAGE_CLASS(T_register, STORAGE_CLASS_REGISTER)
+
+ case T___thread:
+ switch (specifiers->storage_class) {
+ case STORAGE_CLASS_NONE:
+ specifiers->storage_class = STORAGE_CLASS_THREAD;
+ break;
+
+ case STORAGE_CLASS_EXTERN:
+ specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN;
+ break;
+
+ case STORAGE_CLASS_STATIC:
+ specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC;
+ break;
+
+ default:
+ errorf(HERE, "multiple storage classes in declaration specifiers");
+ break;
+ }
+ next_token();
+ break;
+
+ /* type qualifiers */
+#define MATCH_TYPE_QUALIFIER(token, qualifier) \
+ case token: \
+ type_qualifiers |= qualifier; \
+ next_token(); \
+ break;
+
+ MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
+ MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
+ MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+
+ case T___extension__:
+ /* TODO */
+ next_token();
+ break;
+
+ /* type specifiers */
+#define MATCH_SPECIFIER(token, specifier, name) \
+ case token: \
+ next_token(); \
+ if(type_specifiers & specifier) { \
+ errorf(HERE, "multiple " name " type specifiers given"); \
+ } else { \
+ type_specifiers |= specifier; \
+ } \
+ break;
+
+ MATCH_SPECIFIER(T_void, SPECIFIER_VOID, "void")
+ MATCH_SPECIFIER(T_char, SPECIFIER_CHAR, "char")
+ MATCH_SPECIFIER(T_short, SPECIFIER_SHORT, "short")
+ MATCH_SPECIFIER(T_int, SPECIFIER_INT, "int")
+ MATCH_SPECIFIER(T_float, SPECIFIER_FLOAT, "float")
+ MATCH_SPECIFIER(T_double, SPECIFIER_DOUBLE, "double")
+ MATCH_SPECIFIER(T_signed, SPECIFIER_SIGNED, "signed")
+ MATCH_SPECIFIER(T_unsigned, SPECIFIER_UNSIGNED, "unsigned")
+ MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool")
+#ifdef PROVIDE_COMPLEX
+ MATCH_SPECIFIER(T__Complex, SPECIFIER_COMPLEX, "_Complex")
+ MATCH_SPECIFIER(T__Imaginary, SPECIFIER_IMAGINARY, "_Imaginary")
+#endif
+ case T_forceinline:
+ /* only in microsoft mode */
+ specifiers->decl_modifiers |= DM_FORCEINLINE;
+
+ case T_inline:
+ next_token();
+ specifiers->is_inline = true;
+ break;
+
+ case T_long:
+ next_token();
+ if(type_specifiers & SPECIFIER_LONG_LONG) {
+ errorf(HERE, "multiple type specifiers given");
+ } else if(type_specifiers & SPECIFIER_LONG) {
+ type_specifiers |= SPECIFIER_LONG_LONG;
+ } else {
+ type_specifiers |= SPECIFIER_LONG;
+ }
+ break;
+
+ /* TODO: if type != NULL for the following rules should issue
+ * an error */
+ case T_struct: {
+ type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
+
+ type->compound.declaration = parse_compound_type_specifier(true);
+ break;
+ }
+ case T_union: {
+ type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
+
+ type->compound.declaration = parse_compound_type_specifier(false);
+ break;
+ }
+ case T_enum:
+ type = parse_enum_specifier();
+ break;
+ case T___typeof__:
+ type = parse_typeof();
+ break;
+ case T___builtin_va_list:
+ type = duplicate_type(type_valist);
+ next_token();
+ break;
+
+ case T___attribute__:
+ /* TODO */
+ parse_attributes();
+ break;
+
+ case T_IDENTIFIER: {
+ type_t *typedef_type = get_typedef_type(token.v.symbol);
+
+ if(typedef_type == NULL)
+ goto finish_specifiers;
+
+ next_token();
+ type = typedef_type;
+ break;
+ }
+
+ /* function specifier */
+ default:
+ goto finish_specifiers;
+ }
+ }
+
+finish_specifiers:
+
+ if(type == NULL) {
+ atomic_type_kind_t atomic_type;
+
+ /* match valid basic types */
+ switch(type_specifiers) {
+ case SPECIFIER_VOID:
+ atomic_type = ATOMIC_TYPE_VOID;
+ break;
+ case SPECIFIER_CHAR:
+ atomic_type = ATOMIC_TYPE_CHAR;
+ break;
+ case SPECIFIER_SIGNED | SPECIFIER_CHAR:
+ atomic_type = ATOMIC_TYPE_SCHAR;
+ break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_CHAR:
+ atomic_type = ATOMIC_TYPE_UCHAR;
+ break;
+ case SPECIFIER_SHORT:
+ case SPECIFIER_SIGNED | SPECIFIER_SHORT:
+ case SPECIFIER_SHORT | SPECIFIER_INT:
+ case SPECIFIER_SIGNED | SPECIFIER_SHORT | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_SHORT;
+ break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_SHORT:
+ case SPECIFIER_UNSIGNED | SPECIFIER_SHORT | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_USHORT;
+ break;
+ case SPECIFIER_INT:
+ case SPECIFIER_SIGNED:
+ case SPECIFIER_SIGNED | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_INT;
+ break;
+ case SPECIFIER_UNSIGNED:
+ case SPECIFIER_UNSIGNED | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_UINT;
+ break;
+ case SPECIFIER_LONG:
+ case SPECIFIER_SIGNED | SPECIFIER_LONG:
+ case SPECIFIER_LONG | SPECIFIER_INT:
+ case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_LONG;
+ break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_LONG:
+ case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_ULONG;
+ break;
+ case SPECIFIER_LONG | SPECIFIER_LONG_LONG:
+ case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG:
+ case SPECIFIER_LONG | SPECIFIER_LONG_LONG | SPECIFIER_INT:
+ case SPECIFIER_SIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG
+ | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_LONGLONG;
+ break;
+ case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG:
+ case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG
+ | SPECIFIER_INT:
+ atomic_type = ATOMIC_TYPE_ULONGLONG;
+ break;
+ case SPECIFIER_FLOAT:
+ atomic_type = ATOMIC_TYPE_FLOAT;
+ break;
+ case SPECIFIER_DOUBLE:
+ atomic_type = ATOMIC_TYPE_DOUBLE;
+ break;
+ case SPECIFIER_LONG | SPECIFIER_DOUBLE:
+ atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
+ break;
+ case SPECIFIER_BOOL:
+ atomic_type = ATOMIC_TYPE_BOOL;
+ break;
+#ifdef PROVIDE_COMPLEX
+ case SPECIFIER_FLOAT | SPECIFIER_COMPLEX:
+ atomic_type = ATOMIC_TYPE_FLOAT_COMPLEX;
+ break;
+ case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
+ atomic_type = ATOMIC_TYPE_DOUBLE_COMPLEX;
+ break;
+ case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
+ atomic_type = ATOMIC_TYPE_LONG_DOUBLE_COMPLEX;
+ break;
+ case SPECIFIER_FLOAT | SPECIFIER_IMAGINARY:
+ atomic_type = ATOMIC_TYPE_FLOAT_IMAGINARY;
+ break;
+ case SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
+ atomic_type = ATOMIC_TYPE_DOUBLE_IMAGINARY;
+ break;
+ case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
+ atomic_type = ATOMIC_TYPE_LONG_DOUBLE_IMAGINARY;
+ break;
+#endif
+ default:
+ /* invalid specifier combination, give an error message */
+ if(type_specifiers == 0) {
+ if (! strict_mode) {
+ warningf(HERE, "no type specifiers in declaration, using int");
+ atomic_type = ATOMIC_TYPE_INT;
+ break;
+ } else {
+ errorf(HERE, "no type specifiers given in declaration");
+ }
+ } else if((type_specifiers & SPECIFIER_SIGNED) &&
+ (type_specifiers & SPECIFIER_UNSIGNED)) {
+ errorf(HERE, "signed and unsigned specifiers gives");
+ } else if(type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) {
+ errorf(HERE, "only integer types can be signed or unsigned");
+ } else {
+ errorf(HERE, "multiple datatypes in declaration");
+ }
+ atomic_type = ATOMIC_TYPE_INVALID;
+ }
+
+ type = allocate_type_zero(TYPE_ATOMIC);
+ type->atomic.akind = atomic_type;
+ newtype = 1;
+ } else {
+ if(type_specifiers != 0) {
+ errorf(HERE, "multiple datatypes in declaration");
+ }
+ }
+
+ type->base.qualifiers = type_qualifiers;
+
+ type_t *result = typehash_insert(type);
+ if(newtype && result != type) {
+ free_type(type);
+ }
+
+ specifiers->type = result;
+}
+
+static type_qualifiers_t parse_type_qualifiers(void)
+{
+ type_qualifiers_t type_qualifiers = TYPE_QUALIFIER_NONE;
+
+ while(true) {
+ switch(token.type) {
+ /* type qualifiers */
+ MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST);
+ MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT);
+ MATCH_TYPE_QUALIFIER(T_volatile, TYPE_QUALIFIER_VOLATILE);
+
+ default:
+ return type_qualifiers;
+ }
+ }
+}
+
+static declaration_t *parse_identifier_list(void)
+{
+ declaration_t *declarations = NULL;
+ declaration_t *last_declaration = NULL;
+ do {
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->source_position = token.source_position;
+ declaration->symbol = token.v.symbol;
+ next_token();
+
+ if(last_declaration != NULL) {
+ last_declaration->next = declaration;
+ } else {
+ declarations = declaration;
+ }
+ last_declaration = declaration;
+
+ if(token.type != ',')
+ break;
+ next_token();
+ } while(token.type == T_IDENTIFIER);
+
+ return declarations;
+}
+
+static void semantic_parameter(declaration_t *declaration)
+{
+ /* TODO: improve error messages */
+
+ if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+ errorf(HERE, "typedef not allowed in parameter list");
+ } else if(declaration->storage_class != STORAGE_CLASS_NONE
+ && declaration->storage_class != STORAGE_CLASS_REGISTER) {
+ errorf(HERE, "parameter may only have none or register storage class");
+ }
+
+ type_t *orig_type = declaration->type;
+ if(orig_type == NULL)
+ return;
+ type_t *type = skip_typeref(orig_type);
+
+ /* Array as last part of a parameter type is just syntactic sugar. Turn it
+ * into a pointer. § 6.7.5.3 (7) */
+ if (is_type_array(type)) {
+ const array_type_t *arr_type = &type->array;
+ type_t *element_type = arr_type->element_type;
+
+ type = make_pointer_type(element_type, type->base.qualifiers);
+
+ declaration->type = type;
+ }
+
+ if(is_type_incomplete(type)) {
+ errorf(HERE, "incomplete type ('%T') not allowed for parameter '%Y'",
+ orig_type, declaration->symbol);
+ }
+}
+
+static declaration_t *parse_parameter(void)
+{
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+
+ parse_declaration_specifiers(&specifiers);
+
+ declaration_t *declaration = parse_declarator(&specifiers, /*may_be_abstract=*/true);
+
+ semantic_parameter(declaration);
+
+ return declaration;
+}
+
+static declaration_t *parse_parameters(function_type_t *type)
+{
+ if(token.type == T_IDENTIFIER) {
+ symbol_t *symbol = token.v.symbol;
+ if(!is_typedef_symbol(symbol)) {
+ type->kr_style_parameters = true;
+ return parse_identifier_list();
+ }
+ }
+
+ if(token.type == ')') {
+ type->unspecified_parameters = 1;
+ return NULL;
+ }
+ if(token.type == T_void && look_ahead(1)->type == ')') {
+ next_token();
+ return NULL;
+ }
+
+ declaration_t *declarations = NULL;
+ declaration_t *declaration;
+ declaration_t *last_declaration = NULL;
+ function_parameter_t *parameter;
+ function_parameter_t *last_parameter = NULL;
+
+ while(true) {
+ switch(token.type) {
+ case T_DOTDOTDOT:
+ next_token();
+ type->variadic = 1;
+ return declarations;
+
+ case T_IDENTIFIER:
+ case T___extension__:
+ DECLARATION_START
+ declaration = parse_parameter();
+
+ parameter = obstack_alloc(type_obst, sizeof(parameter[0]));
+ memset(parameter, 0, sizeof(parameter[0]));
+ parameter->type = declaration->type;
+
+ if(last_parameter != NULL) {
+ last_declaration->next = declaration;
+ last_parameter->next = parameter;
+ } else {
+ type->parameters = parameter;
+ declarations = declaration;
+ }
+ last_parameter = parameter;
+ last_declaration = declaration;
+ break;
+
+ default:
+ return declarations;
+ }
+ if(token.type != ',')
+ return declarations;
+ next_token();
+ }
+}
+
+typedef enum {
+ CONSTRUCT_INVALID,
+ CONSTRUCT_POINTER,
+ CONSTRUCT_FUNCTION,
+ CONSTRUCT_ARRAY
+} construct_type_type_t;
+
+typedef struct construct_type_t construct_type_t;
+struct construct_type_t {
+ construct_type_type_t type;
+ construct_type_t *next;
+};
+
+typedef struct parsed_pointer_t parsed_pointer_t;
+struct parsed_pointer_t {
+ construct_type_t construct_type;
+ type_qualifiers_t type_qualifiers;
+};
+
+typedef struct construct_function_type_t construct_function_type_t;
+struct construct_function_type_t {
+ construct_type_t construct_type;
+ type_t *function_type;
+};
+
+typedef struct parsed_array_t parsed_array_t;
+struct parsed_array_t {
+ construct_type_t construct_type;
+ type_qualifiers_t type_qualifiers;
+ bool is_static;
+ bool is_variable;
+ expression_t *size;
+};
+
+typedef struct construct_base_type_t construct_base_type_t;
+struct construct_base_type_t {
+ construct_type_t construct_type;
+ type_t *type;
+};
+
+static construct_type_t *parse_pointer_declarator(void)
+{
+ eat('*');
+
+ parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
+ memset(pointer, 0, sizeof(pointer[0]));
+ pointer->construct_type.type = CONSTRUCT_POINTER;
+ pointer->type_qualifiers = parse_type_qualifiers();
+
+ return (construct_type_t*) pointer;
+}
+
+static construct_type_t *parse_array_declarator(void)
+{
+ eat('[');
+
+ parsed_array_t *array = obstack_alloc(&temp_obst, sizeof(array[0]));
+ memset(array, 0, sizeof(array[0]));
+ array->construct_type.type = CONSTRUCT_ARRAY;
+
+ if(token.type == T_static) {
+ array->is_static = true;
+ next_token();
+ }
+
+ type_qualifiers_t type_qualifiers = parse_type_qualifiers();
+ if(type_qualifiers != 0) {
+ if(token.type == T_static) {
+ array->is_static = true;
+ next_token();
+ }
+ }
+ array->type_qualifiers = type_qualifiers;
+
+ if(token.type == '*' && look_ahead(1)->type == ']') {
+ array->is_variable = true;
+ next_token();
+ } else if(token.type != ']') {
+ array->size = parse_assignment_expression();
+ }
+
+ expect(']');
+
+ return (construct_type_t*) array;
+}
+
+static construct_type_t *parse_function_declarator(declaration_t *declaration)
+{
+ eat('(');
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+
+ declaration_t *parameters = parse_parameters(&type->function);
+ if(declaration != NULL) {
+ declaration->context.declarations = parameters;
+ }
+
+ construct_function_type_t *construct_function_type =
+ obstack_alloc(&temp_obst, sizeof(construct_function_type[0]));
+ memset(construct_function_type, 0, sizeof(construct_function_type[0]));
+ construct_function_type->construct_type.type = CONSTRUCT_FUNCTION;
+ construct_function_type->function_type = type;
+
+ expect(')');
+
+ return (construct_type_t*) construct_function_type;
+}
+
+static construct_type_t *parse_inner_declarator(declaration_t *declaration,
+ bool may_be_abstract)
+{
+ /* construct a single linked list of construct_type_t's which describe
+ * how to construct the final declarator type */
+ construct_type_t *first = NULL;
+ construct_type_t *last = NULL;
+
+ /* pointers */
+ while(token.type == '*') {
+ construct_type_t *type = parse_pointer_declarator();
+
+ if(last == NULL) {
+ first = type;
+ last = type;
+ } else {
+ last->next = type;
+ last = type;
+ }
+ }
+
+ /* TODO: find out if this is correct */
+ parse_attributes();
+
+ construct_type_t *inner_types = NULL;
+
+ switch(token.type) {
+ case T_IDENTIFIER:
+ if(declaration == NULL) {
+ errorf(HERE, "no identifier expected in typename");
+ } else {
+ declaration->symbol = token.v.symbol;
+ declaration->source_position = token.source_position;
+ }
+ next_token();
+ break;
+ case '(':
+ next_token();
+ inner_types = parse_inner_declarator(declaration, may_be_abstract);
+ expect(')');
+ break;
+ default:
+ if(may_be_abstract)
+ break;
+ parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', 0);
+ /* avoid a loop in the outermost scope, because eat_statement doesn't
+ * eat '}' */
+ if(token.type == '}' && current_function == NULL) {
+ next_token();
+ } else {
+ eat_statement();
+ }
+ return NULL;
+ }
+
+ construct_type_t *p = last;
+
+ while(true) {
+ construct_type_t *type;
+ switch(token.type) {
+ case '(':
+ type = parse_function_declarator(declaration);
+ break;
+ case '[':
+ type = parse_array_declarator();
+ break;
+ default:
+ goto declarator_finished;
+ }
+
+ /* insert in the middle of the list (behind p) */
+ if(p != NULL) {
+ type->next = p->next;
+ p->next = type;
+ } else {
+ type->next = first;
+ first = type;
+ }
+ if(last == p) {
+ last = type;
+ }
+ }
+
+declarator_finished:
+ parse_attributes();
+
+ /* append inner_types at the end of the list, we don't to set last anymore
+ * as it's not needed anymore */
+ if(last == NULL) {
+ assert(first == NULL);
+ first = inner_types;
+ } else {
+ last->next = inner_types;
+ }
+
+ return first;
+}
+
+static type_t *construct_declarator_type(construct_type_t *construct_list,
+ type_t *type)
+{
+ construct_type_t *iter = construct_list;
+ for( ; iter != NULL; iter = iter->next) {
+ switch(iter->type) {
+ case CONSTRUCT_INVALID:
+ panic("invalid type construction found");
+ case CONSTRUCT_FUNCTION: {
+ construct_function_type_t *construct_function_type
+ = (construct_function_type_t*) iter;
+
+ type_t *function_type = construct_function_type->function_type;
+
+ function_type->function.return_type = type;
+
+ type = function_type;
+ break;
+ }
+
+ case CONSTRUCT_POINTER: {
+ parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
+ type_t *pointer_type = allocate_type_zero(TYPE_POINTER);
+ pointer_type->pointer.points_to = type;
+ pointer_type->base.qualifiers = parsed_pointer->type_qualifiers;
+
+ type = pointer_type;
+ break;
+ }
+
+ case CONSTRUCT_ARRAY: {
+ parsed_array_t *parsed_array = (parsed_array_t*) iter;
+ type_t *array_type = allocate_type_zero(TYPE_ARRAY);
+
+ array_type->base.qualifiers = parsed_array->type_qualifiers;
+ array_type->array.element_type = type;
+ array_type->array.is_static = parsed_array->is_static;
+ array_type->array.is_variable = parsed_array->is_variable;
+ array_type->array.size = parsed_array->size;
+
+ type = array_type;
+ break;
+ }
+ }
+
+ type_t *hashed_type = typehash_insert(type);
+ if(hashed_type != type) {
+ /* the function type was constructed earlier freeing it here will
+ * destroy other types... */
+ if(iter->type != CONSTRUCT_FUNCTION) {
+ free_type(type);
+ }
+ type = hashed_type;
+ }
+ }
+
+ return type;
+}
+
+static declaration_t *parse_declarator(
+ const declaration_specifiers_t *specifiers, bool may_be_abstract)
+{
+ type_t *type = specifiers->type;
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration->storage_class = specifiers->storage_class;
+ declaration->modifiers = specifiers->decl_modifiers;
+ declaration->is_inline = specifiers->is_inline;
+
+ construct_type_t *construct_type
+ = parse_inner_declarator(declaration, may_be_abstract);
+ declaration->type = construct_declarator_type(construct_type, type);
+
+ if(construct_type != NULL) {
+ obstack_free(&temp_obst, construct_type);
+ }
+
+ return declaration;
+}
+
+static type_t *parse_abstract_declarator(type_t *base_type)
+{
+ construct_type_t *construct_type = parse_inner_declarator(NULL, 1);
+
+ type_t *result = construct_declarator_type(construct_type, base_type);
+ if(construct_type != NULL) {
+ obstack_free(&temp_obst, construct_type);
+ }
+
+ return result;
+}
+
+static declaration_t *append_declaration(declaration_t* const declaration)
+{
+ if (last_declaration != NULL) {
+ last_declaration->next = declaration;
+ } else {
+ context->declarations = declaration;
+ }
+ last_declaration = declaration;
+ return declaration;
+}
+
+static declaration_t *internal_record_declaration(
+ declaration_t *const declaration,
+ const bool is_function_definition)
+{
+ const symbol_t *const symbol = declaration->symbol;
+ const namespace_t namespc = (namespace_t)declaration->namespc;
+
+ const type_t *const type = skip_typeref(declaration->type);
+ if (is_type_function(type) && type->function.unspecified_parameters) {
+ warningf(declaration->source_position,
+ "function declaration '%#T' is not a prototype",
+ type, declaration->symbol);
+ }
+
+ declaration_t *const previous_declaration = get_declaration(symbol, namespc);
+ assert(declaration != previous_declaration);
+ if (previous_declaration != NULL
+ && previous_declaration->parent_context == context) {
+ /* can happen for K&R style declarations */
+ if(previous_declaration->type == NULL) {
+ previous_declaration->type = declaration->type;
+ }
+
+ const type_t *const prev_type = skip_typeref(previous_declaration->type);
+ if (!types_compatible(type, prev_type)) {
+ errorf(declaration->source_position,
+ "declaration '%#T' is incompatible with previous declaration '%#T'",
+ type, symbol, previous_declaration->type, symbol);
+ errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ } else {
+ unsigned old_storage_class = previous_declaration->storage_class;
+ unsigned new_storage_class = declaration->storage_class;
+
+ /* pretend no storage class means extern for function declarations
+ * (except if the previous declaration is neither none nor extern) */
+ if (is_type_function(type)) {
+ switch (old_storage_class) {
+ case STORAGE_CLASS_NONE:
+ old_storage_class = STORAGE_CLASS_EXTERN;
+
+ case STORAGE_CLASS_EXTERN:
+ if (new_storage_class == STORAGE_CLASS_NONE && !is_function_definition) {
+ new_storage_class = STORAGE_CLASS_EXTERN;
+ }
+ break;
+
+ default: break;
+ }
+ }
+
+ if (old_storage_class == STORAGE_CLASS_EXTERN &&
+ new_storage_class == STORAGE_CLASS_EXTERN) {
+warn_redundant_declaration:
+ warningf(declaration->source_position, "redundant declaration for '%Y'", symbol);
+ warningf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ } else if (current_function == NULL) {
+ if (old_storage_class != STORAGE_CLASS_STATIC &&
+ new_storage_class == STORAGE_CLASS_STATIC) {
+ errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
+ errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ } else {
+ if (old_storage_class != STORAGE_CLASS_EXTERN) {
+ goto warn_redundant_declaration;
+ }
+ if (new_storage_class == STORAGE_CLASS_NONE) {
+ previous_declaration->storage_class = STORAGE_CLASS_NONE;
+ }
+ }
+ } else {
+ if (old_storage_class == new_storage_class) {
+ errorf(declaration->source_position, "redeclaration of '%Y'", symbol);
+ } else {
+ errorf(declaration->source_position, "redeclaration of '%Y' with different linkage", symbol);
+ }
+ errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+ }
+ }
+ return previous_declaration;
+ }
+
+ assert(declaration->parent_context == NULL);
+ assert(declaration->symbol != NULL);
+ assert(context != NULL);
+
+ declaration->parent_context = context;
+
+ environment_push(declaration);
+ return append_declaration(declaration);
+}
+
+static declaration_t *record_declaration(declaration_t *declaration)
+{
+ return internal_record_declaration(declaration, false);
+}
+
+static declaration_t *record_function_definition(declaration_t *const declaration)
+{
+ return internal_record_declaration(declaration, true);
+}
+
+static void parser_error_multiple_definition(declaration_t *declaration,
+ const source_position_t source_position)
+{
+ errorf(source_position, "multiple definition of symbol '%Y'",
+ declaration->symbol);
+ errorf(declaration->source_position,
+ "this is the location of the previous definition.");
+}
+
+static bool is_declaration_specifier(const token_t *token,
+ bool only_type_specifiers)
+{
+ switch(token->type) {
+ TYPE_SPECIFIERS
+ return true;
+ case T_IDENTIFIER:
+ return is_typedef_symbol(token->v.symbol);
+
+ case T___extension__:
+ STORAGE_CLASSES
+ TYPE_QUALIFIERS
+ return !only_type_specifiers;
+
+ default:
+ return false;
+ }
+}
+
+static void parse_init_declarator_rest(declaration_t *declaration)
+{
+ eat('=');
+
+ type_t *orig_type = declaration->type;
+ type_t *type = NULL;
+ if(orig_type != NULL)
+ type = skip_typeref(orig_type);
+
+ if(declaration->init.initializer != NULL) {
+ parser_error_multiple_definition(declaration, token.source_position);
+ }
+
+ initializer_t *initializer = parse_initializer(type);
+
+ /* § 6.7.5 (22) array initializers for arrays with unknown size determine
+ * the array type size */
+ if(type != NULL && is_type_array(type) && initializer != NULL) {
+ array_type_t *array_type = &type->array;
+
+ if(array_type->size == NULL) {
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+
+ cnst->base.datatype = type_size_t;
+
+ switch (initializer->kind) {
+ case INITIALIZER_LIST: {
+ initializer_list_t *const list = &initializer->list;
+ cnst->conste.v.int_value = list->len;
+ break;
+ }
+
+ case INITIALIZER_STRING: {
+ initializer_string_t *const string = &initializer->string;
+ cnst->conste.v.int_value = strlen(string->string) + 1;
+ break;
+ }
+
+ case INITIALIZER_WIDE_STRING: {
+ initializer_wide_string_t *const string = &initializer->wide_string;
+ cnst->conste.v.int_value = string->string.size;
+ break;
+ }
+
+ default:
+ panic("invalid initializer type");
+ }
+
+ array_type->size = cnst;
+ }
+ }
+
+ if(type != NULL && is_type_function(type)) {
+ errorf(declaration->source_position,
+ "initializers not allowed for function types at declator '%Y' (type '%T')",
+ declaration->symbol, orig_type);
+ } else {
+ declaration->init.initializer = initializer;
+ }
+}
+
+/* parse rest of a declaration without any declarator */
+static void parse_anonymous_declaration_rest(
+ const declaration_specifiers_t *specifiers,
+ parsed_declaration_func finished_declaration)
+{
+ eat(';');
+
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->type = specifiers->type;
+ declaration->storage_class = specifiers->storage_class;
+ declaration->source_position = specifiers->source_position;
+
+ if (declaration->storage_class != STORAGE_CLASS_NONE) {
+ warningf(declaration->source_position, "useless storage class in empty declaration");
+ }
+
+ type_t *type = declaration->type;
+ switch (type->kind) {
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: {
+ const compound_type_t *compound_type = &type->compound;
+ if (compound_type->declaration->symbol == NULL) {
+ warningf(declaration->source_position, "unnamed struct/union that defines no instances");
+ }
+ break;
+ }
+
+ case TYPE_ENUM:
+ break;
+
+ default:
+ warningf(declaration->source_position, "empty declaration");
+ break;
+ }
+
+ finished_declaration(declaration);
+}
+
+static void parse_declaration_rest(declaration_t *ndeclaration,
+ const declaration_specifiers_t *specifiers,
+ parsed_declaration_func finished_declaration)
+{
+ while(true) {
+ declaration_t *declaration = finished_declaration(ndeclaration);
+
+ type_t *orig_type = declaration->type;
+ type_t *type = skip_typeref(orig_type);
+
+ if(type->kind != TYPE_FUNCTION && declaration->is_inline) {
+ warningf(declaration->source_position,
+ "variable '%Y' declared 'inline'\n", declaration->symbol);
+ }
+
+ if(token.type == '=') {
+ parse_init_declarator_rest(declaration);
+ }
+
+ if(token.type != ',')
+ break;
+ eat(',');
+
+ ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false);
+ }
+ expect_void(';');
+}
+
+static declaration_t *finished_kr_declaration(declaration_t *declaration)
+{
+ symbol_t *symbol = declaration->symbol;
+ if(symbol == NULL) {
+ errorf(HERE, "anonymous declaration not valid as function parameter");
+ return declaration;
+ }
+ namespace_t namespc = (namespace_t) declaration->namespc;
+ if(namespc != NAMESPACE_NORMAL) {
+ return record_declaration(declaration);
+ }
+
+ declaration_t *previous_declaration = get_declaration(symbol, namespc);
+ if(previous_declaration == NULL ||
+ previous_declaration->parent_context != context) {
+ errorf(HERE, "expected declaration of a function parameter, found '%Y'",
+ symbol);
+ return declaration;
+ }
+
+ if(previous_declaration->type == NULL) {
+ previous_declaration->type = declaration->type;
+ previous_declaration->storage_class = declaration->storage_class;
+ previous_declaration->parent_context = context;
+ return previous_declaration;
+ } else {
+ return record_declaration(declaration);
+ }
+}
+
+static void parse_declaration(parsed_declaration_func finished_declaration)
+{
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+
+ if(token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers, finished_declaration);
+ } else {
+ declaration_t *declaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
+ parse_declaration_rest(declaration, &specifiers, finished_declaration);
+ }
+}
+
+static void parse_kr_declaration_list(declaration_t *declaration)
+{
+ type_t *type = skip_typeref(declaration->type);
+ if(!is_type_function(type))
+ return;
+
+ if(!type->function.kr_style_parameters)
+ return;
+
+ /* push function parameters */
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ assert(parameter->parent_context == NULL);
+ parameter->parent_context = context;
+ environment_push(parameter);
+ }
+
+ /* parse declaration list */
+ while(is_declaration_specifier(&token, false)) {
+ parse_declaration(finished_kr_declaration);
+ }
+
+ /* pop function parameters */
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+
+ /* update function type */
+ type_t *new_type = duplicate_type(type);
+ new_type->function.kr_style_parameters = false;
+
+ function_parameter_t *parameters = NULL;
+ function_parameter_t *last_parameter = NULL;
+
+ declaration_t *parameter_declaration = declaration->context.declarations;
+ for( ; parameter_declaration != NULL;
+ parameter_declaration = parameter_declaration->next) {
+ type_t *parameter_type = parameter_declaration->type;
+ if(parameter_type == NULL) {
+ if (strict_mode) {
+ errorf(HERE, "no type specified for function parameter '%Y'",
+ parameter_declaration->symbol);
+ } else {
+ warningf(HERE, "no type specified for function parameter '%Y', using int",
+ parameter_declaration->symbol);
+ parameter_type = type_int;
+ parameter_declaration->type = parameter_type;
+ }
+ }
+
+ semantic_parameter(parameter_declaration);
+ parameter_type = parameter_declaration->type;
+
+ function_parameter_t *function_parameter
+ = obstack_alloc(type_obst, sizeof(function_parameter[0]));
+ memset(function_parameter, 0, sizeof(function_parameter[0]));
+
+ function_parameter->type = parameter_type;
+ if(last_parameter != NULL) {
+ last_parameter->next = function_parameter;
+ } else {
+ parameters = function_parameter;
+ }
+ last_parameter = function_parameter;
+ }
+ new_type->function.parameters = parameters;
+
+ type = typehash_insert(new_type);
+ if(type != new_type) {
+ obstack_free(type_obst, new_type);
+ }
+
+ declaration->type = type;
+}
+
+static void parse_external_declaration(void)
+{
+ /* function-definitions and declarations both start with declaration
+ * specifiers */
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+
+ /* must be a declaration */
+ if(token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers, append_declaration);
+ return;
+ }
+
+ /* declarator is common to both function-definitions and declarations */
+ declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
+
+ /* must be a declaration */
+ if(token.type == ',' || token.type == '=' || token.type == ';') {
+ parse_declaration_rest(ndeclaration, &specifiers, record_declaration);
+ return;
+ }
+
+ /* must be a function definition */
+ parse_kr_declaration_list(ndeclaration);
+
+ if(token.type != '{') {
+ parse_error_expected("while parsing function definition", '{', 0);
+ eat_statement();
+ return;
+ }
+
+ type_t *type = ndeclaration->type;
+ if(type == NULL) {
+ eat_block();
+ return;
+ }
+
+ /* note that we don't skip typerefs: the standard doesn't allow them here
+ * (so we can't use is_type_function here) */
+ if(type->kind != TYPE_FUNCTION) {
+ errorf(HERE, "declarator '%#T' has a body but is not a function type",
+ type, ndeclaration->symbol);
+ eat_block();
+ return;
+ }
+
+ /* § 6.7.5.3 (14) a function definition with () means no
+ * parameters (and not unspecified parameters) */
+ if(type->function.unspecified_parameters) {
+ type_t *duplicate = duplicate_type(type);
+ duplicate->function.unspecified_parameters = false;
+
+ type = typehash_insert(duplicate);
+ if(type != duplicate) {
+ obstack_free(type_obst, duplicate);
+ }
+ ndeclaration->type = type;
+ }
+
+ declaration_t *const declaration = record_function_definition(ndeclaration);
+ if(ndeclaration != declaration) {
+ declaration->context = ndeclaration->context;
+ }
+ type = skip_typeref(declaration->type);
+
+ /* push function parameters and switch context */
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ if(parameter->parent_context == &ndeclaration->context) {
+ parameter->parent_context = context;
+ }
+ assert(parameter->parent_context == NULL
+ || parameter->parent_context == context);
+ parameter->parent_context = context;
+ environment_push(parameter);
+ }
+
+ if(declaration->init.statement != NULL) {
+ parser_error_multiple_definition(declaration, token.source_position);
+ eat_block();
+ goto end_of_parse_external_declaration;
+ } else {
+ /* parse function body */
+ int label_stack_top = label_top();
+ declaration_t *old_current_function = current_function;
+ current_function = declaration;
+
+ declaration->init.statement = parse_compound_statement();
+
+ assert(current_function == declaration);
+ current_function = old_current_function;
+ label_pop_to(label_stack_top);
+ }
+
+end_of_parse_external_declaration:
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+}
+
+static type_t *make_bitfield_type(type_t *base, expression_t *size)
+{
+ type_t *type = allocate_type_zero(TYPE_BITFIELD);
+ type->bitfield.base = base;
+ type->bitfield.size = size;
+
+ return type;
+}
+
+static void parse_struct_declarators(const declaration_specifiers_t *specifiers)
+{
+ /* TODO: check constraints for struct declarations (in specifiers) */
+ while(1) {
+ declaration_t *declaration;
+
+ if(token.type == ':') {
+ next_token();
+
+ type_t *base_type = specifiers->type;
+ expression_t *size = parse_constant_expression();
+
+ type_t *type = make_bitfield_type(base_type, size);
+
+ declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->namespc = NAMESPACE_NORMAL;
+ declaration->storage_class = STORAGE_CLASS_NONE;
+ declaration->source_position = token.source_position;
+ declaration->modifiers = specifiers->decl_modifiers;
+ declaration->type = type;
+
+ record_declaration(declaration);
+ } else {
+ declaration = parse_declarator(specifiers,/*may_be_abstract=*/true);
+
+ if(token.type == ':') {
+ next_token();
+ expression_t *size = parse_constant_expression();
+
+ type_t *type = make_bitfield_type(declaration->type, size);
+ declaration->type = type;
+ }
+ }
+ record_declaration(declaration);
+
+ if(token.type != ',')
+ break;
+ next_token();
+ }
+ expect_void(';');
+}
+
+static void parse_compound_type_entries(void)
+{
+ eat('{');
+
+ while(token.type != '}' && token.type != T_EOF) {
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+
+ parse_struct_declarators(&specifiers);
+ }
+ if(token.type == T_EOF) {
+ errorf(HERE, "EOF while parsing struct");
+ }
+ next_token();
+}
+
+static type_t *parse_typename(void)
+{
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+ if(specifiers.storage_class != STORAGE_CLASS_NONE) {
+ /* TODO: improve error message, user does probably not know what a
+ * storage class is...
+ */
+ errorf(HERE, "typename may not have a storage class");
+ }
+
+ type_t *result = parse_abstract_declarator(specifiers.type);
+
+ return result;
+}
+
+
+
+
+typedef expression_t* (*parse_expression_function) (unsigned precedence);
+typedef expression_t* (*parse_expression_infix_function) (unsigned precedence,
+ expression_t *left);
+
+typedef struct expression_parser_function_t expression_parser_function_t;
+struct expression_parser_function_t {
+ unsigned precedence;
+ parse_expression_function parser;
+ unsigned infix_precedence;
+ parse_expression_infix_function infix_parser;
+};
+
+expression_parser_function_t expression_parsers[T_LAST_TOKEN];
+
+/**
+ * Creates a new invalid expression.
+ */
+static expression_t *create_invalid_expression(void)
+{
+ expression_t *expression = allocate_expression_zero(EXPR_INVALID);
+ expression->base.source_position = token.source_position;
+ return expression;
+}
+
+static expression_t *expected_expression_error(void)
+{
+ errorf(HERE, "expected expression, got token '%K'", &token);
+
+ next_token();
+
+ return create_invalid_expression();
+}
+
+/**
+ * Parse a string constant.
+ */
+static expression_t *parse_string_const(void)
+{
+ expression_t *cnst = allocate_expression_zero(EXPR_STRING_LITERAL);
+ cnst->base.datatype = type_string;
+ cnst->string.value = parse_string_literals();
+
+ return cnst;
+}
+
+/**
+ * Parse a wide string constant.
+ */
+static expression_t *parse_wide_string_const(void)
+{
+ expression_t *const cnst = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL);
+ cnst->base.datatype = type_wchar_t_ptr;
+ cnst->wide_string.value = token.v.wide_string; /* TODO concatenate */
+ next_token();
+ return cnst;
+}
+
+/**
+ * Parse an integer constant.
+ */
+static expression_t *parse_int_const(void)
+{
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+ cnst->base.datatype = token.datatype;
+ cnst->conste.v.int_value = token.v.intvalue;
+
+ next_token();
+
+ return cnst;
+}
+
+/**
+ * Parse a float constant.
+ */
+static expression_t *parse_float_const(void)
+{
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+ cnst->base.datatype = token.datatype;
+ cnst->conste.v.float_value = token.v.floatvalue;
+
+ next_token();
+
+ return cnst;
+}
+
+static declaration_t *create_implicit_function(symbol_t *symbol,
+ const source_position_t source_position)
+{
+ type_t *ntype = allocate_type_zero(TYPE_FUNCTION);
+ ntype->function.return_type = type_int;
+ ntype->function.unspecified_parameters = true;
+
+ type_t *type = typehash_insert(ntype);
+ if(type != ntype) {
+ free_type(ntype);
+ }
+
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->storage_class = STORAGE_CLASS_EXTERN;
+ declaration->type = type;
+ declaration->symbol = symbol;
+ declaration->source_position = source_position;
+ declaration->parent_context = global_context;
+
+ context_t *old_context = context;
+ set_context(global_context);
+
+ environment_push(declaration);
+ /* prepend the declaration to the global declarations list */
+ declaration->next = context->declarations;
+ context->declarations = declaration;
+
+ assert(context == global_context);
+ set_context(old_context);
+
+ return declaration;
+}
+
+/**
+ * Creates a return_type (func)(argument_type) function type if not
+ * already exists.
+ *
+ * @param return_type the return type
+ * @param argument_type the argument type
+ */
+static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
+{
+ function_parameter_t *parameter
+ = obstack_alloc(type_obst, sizeof(parameter[0]));
+ memset(parameter, 0, sizeof(parameter[0]));
+ parameter->type = argument_type;
+
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
+ type->function.return_type = return_type;
+ type->function.parameters = parameter;
+
+ type_t *result = typehash_insert(type);
+ if(result != type) {
+ free_type(type);
+ }
+
+ return result;
+}
+
+/**
+ * Creates a function type for some function like builtins.
+ *
+ * @param symbol the symbol describing the builtin
+ */
+static type_t *get_builtin_symbol_type(symbol_t *symbol)
+{
+ switch(symbol->ID) {
+ case T___builtin_alloca:
+ return make_function_1_type(type_void_ptr, type_size_t);
+ case T___builtin_nan:
+ return make_function_1_type(type_double, type_string);
+ case T___builtin_nanf:
+ return make_function_1_type(type_float, type_string);
+ case T___builtin_nand:
+ return make_function_1_type(type_long_double, type_string);
+ case T___builtin_va_end:
+ return make_function_1_type(type_void, type_valist);
+ default:
+ panic("not implemented builtin symbol found");
+ }
+}
+
+/**
+ * Performs automatic type cast as described in § 6.3.2.1.
+ *
+ * @param orig_type the original type
+ */
+static type_t *automatic_type_conversion(type_t *orig_type)
+{
+ if(orig_type == NULL)
+ return NULL;
+
+ type_t *type = skip_typeref(orig_type);
+ if(is_type_array(type)) {
+ array_type_t *array_type = &type->array;
+ type_t *element_type = array_type->element_type;
+ unsigned qualifiers = array_type->type.qualifiers;
+
+ return make_pointer_type(element_type, qualifiers);
+ }
+
+ if(is_type_function(type)) {
+ return make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
+ }
+
+ return orig_type;
+}
+
+/**
+ * reverts the automatic casts of array to pointer types and function
+ * to function-pointer types as defined § 6.3.2.1
+ */
+type_t *revert_automatic_type_conversion(const expression_t *expression)
+{
+ if(expression->base.datatype == NULL)
+ return NULL;
+
+ switch(expression->kind) {
+ case EXPR_REFERENCE: {
+ const reference_expression_t *ref = &expression->reference;
+ return ref->declaration->type;
+ }
+ case EXPR_SELECT: {
+ const select_expression_t *select = &expression->select;
+ return select->compound_entry->type;
+ }
+ case EXPR_UNARY_DEREFERENCE: {
+ expression_t *value = expression->unary.value;
+ type_t *type = skip_typeref(value->base.datatype);
+ pointer_type_t *pointer_type = &type->pointer;
+
+ return pointer_type->points_to;
+ }
+ case EXPR_BUILTIN_SYMBOL: {
+ const builtin_symbol_expression_t *builtin
+ = &expression->builtin_symbol;
+ return get_builtin_symbol_type(builtin->symbol);
+ }
+ case EXPR_ARRAY_ACCESS: {
+ const array_access_expression_t *array_access
+ = &expression->array_access;
+ const expression_t *array_ref = array_access->array_ref;
+ type_t *type_left = skip_typeref(array_ref->base.datatype);
+ assert(is_type_pointer(type_left));
+ pointer_type_t *pointer_type = &type_left->pointer;
+ return pointer_type->points_to;
+ }
+
+ default:
+ break;
+ }
+
+ return expression->base.datatype;
+}
+
+static expression_t *parse_reference(void)
+{
+ expression_t *expression = allocate_expression_zero(EXPR_REFERENCE);
+
+ reference_expression_t *ref = &expression->reference;
+ ref->symbol = token.v.symbol;
+
+ declaration_t *declaration = get_declaration(ref->symbol, NAMESPACE_NORMAL);
+
+ source_position_t source_position = token.source_position;
+ next_token();
+
+ if(declaration == NULL) {
+ if (! strict_mode && token.type == '(') {
+ /* an implicitly defined function */
+ warningf(HERE, "implicit declaration of function '%Y'",
+ ref->symbol);
+
+ declaration = create_implicit_function(ref->symbol,
+ source_position);
+ } else {
+ errorf(HERE, "unknown symbol '%Y' found.", ref->symbol);
+ return expression;
+ }
+ }
+
+ type_t *type = declaration->type;
+
+ /* we always do the auto-type conversions; the & and sizeof parser contains
+ * code to revert this! */
+ type = automatic_type_conversion(type);
+
+ ref->declaration = declaration;
+ ref->expression.datatype = type;
+
+ return expression;
+}
+
+static void check_cast_allowed(expression_t *expression, type_t *dest_type)
+{
+ (void) expression;
+ (void) dest_type;
+ /* TODO check if explicit cast is allowed and issue warnings/errors */
+}
+
+static expression_t *parse_cast(void)
+{
+ expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+
+ cast->base.source_position = token.source_position;
+
+ type_t *type = parse_typename();
+
+ expect(')');
+ expression_t *value = parse_sub_expression(20);
+
+ check_cast_allowed(value, type);
+
+ cast->base.datatype = type;
+ cast->unary.value = value;
+
+ return cast;
+}
+
+static expression_t *parse_statement_expression(void)
+{
+ expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
+
+ statement_t *statement = parse_compound_statement();
+ expression->statement.statement = statement;
+ if(statement == NULL) {
+ expect(')');
+ return NULL;
+ }
+
+ assert(statement->kind == STATEMENT_COMPOUND);
+ compound_statement_t *compound_statement = &statement->compound;
+
+ /* find last statement and use it's type */
+ const statement_t *last_statement = NULL;
+ const statement_t *iter = compound_statement->statements;
+ for( ; iter != NULL; iter = iter->base.next) {
+ last_statement = iter;
+ }
+
+ if(last_statement->kind == STATEMENT_EXPRESSION) {
+ const expression_statement_t *expression_statement
+ = &last_statement->expression;
+ expression->base.datatype
+ = expression_statement->expression->base.datatype;
+ } else {
+ expression->base.datatype = type_void;
+ }
+
+ expect(')');
+
+ return expression;
+}
+
+static expression_t *parse_brace_expression(void)
+{
+ eat('(');
+
+ switch(token.type) {
+ case '{':
+ /* gcc extension: a statement expression */
+ return parse_statement_expression();
+
+ TYPE_QUALIFIERS
+ TYPE_SPECIFIERS
+ return parse_cast();
+ case T_IDENTIFIER:
+ if(is_typedef_symbol(token.v.symbol)) {
+ return parse_cast();
+ }
+ }
+
+ expression_t *result = parse_expression();
+ expect(')');
+
+ return result;
+}
+
+static expression_t *parse_function_keyword(void)
+{
+ next_token();
+ /* TODO */
+
+ if (current_function == NULL) {
+ errorf(HERE, "'__func__' used outside of a function");
+ }
+
+ string_literal_expression_t *expression
+ = allocate_ast_zero(sizeof(expression[0]));
+
+ expression->expression.kind = EXPR_FUNCTION;
+ expression->expression.datatype = type_string;
+ expression->value = current_function->symbol->string;
+
+ return (expression_t*) expression;
+}
+
+static expression_t *parse_pretty_function_keyword(void)
+{
+ eat(T___PRETTY_FUNCTION__);
+ /* TODO */
+
+ if (current_function == NULL) {
+ errorf(HERE, "'__PRETTY_FUNCTION__' used outside of a function");
+ }
+
+ string_literal_expression_t *expression
+ = allocate_ast_zero(sizeof(expression[0]));
+
+ expression->expression.kind = EXPR_PRETTY_FUNCTION;
+ expression->expression.datatype = type_string;
+ expression->value = current_function->symbol->string;
+
+ return (expression_t*) expression;
+}
+
+static designator_t *parse_designator(void)
+{
+ designator_t *result = allocate_ast_zero(sizeof(result[0]));
+
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing member designator",
+ T_IDENTIFIER, 0);
+ eat_paren();
+ return NULL;
+ }
+ result->symbol = token.v.symbol;
+ next_token();
+
+ designator_t *last_designator = result;
+ while(true) {
+ if(token.type == '.') {
+ next_token();
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing member designator",
+ T_IDENTIFIER, 0);
+ eat_paren();
+ return NULL;
+ }
+ designator_t *designator = allocate_ast_zero(sizeof(result[0]));
+ designator->symbol = token.v.symbol;
+ next_token();
+
+ last_designator->next = designator;
+ last_designator = designator;
+ continue;
+ }
+ if(token.type == '[') {
+ next_token();
+ designator_t *designator = allocate_ast_zero(sizeof(result[0]));
+ designator->array_access = parse_expression();
+ if(designator->array_access == NULL) {
+ eat_paren();
+ return NULL;
+ }
+ expect(']');
+
+ last_designator->next = designator;
+ last_designator = designator;
+ continue;
+ }
+ break;
+ }
+
+ return result;
+}
+
+static expression_t *parse_offsetof(void)
+{
+ eat(T___builtin_offsetof);
+
+ expression_t *expression = allocate_expression_zero(EXPR_OFFSETOF);
+ expression->base.datatype = type_size_t;
+
+ expect('(');
+ expression->offsetofe.type = parse_typename();
+ expect(',');
+ expression->offsetofe.designator = parse_designator();
+ expect(')');
+
+ return expression;
+}
+
+static expression_t *parse_va_start(void)
+{
+ eat(T___builtin_va_start);
+
+ expression_t *expression = allocate_expression_zero(EXPR_VA_START);
+
+ expect('(');
+ expression->va_starte.ap = parse_assignment_expression();
+ expect(',');
+ expression_t *const expr = parse_assignment_expression();
+ if (expr->kind == EXPR_REFERENCE) {
+ declaration_t *const decl = expr->reference.declaration;
+ if (decl->parent_context == ¤t_function->context &&
+ decl->next == NULL) {
+ expression->va_starte.parameter = decl;
+ expect(')');
+ return expression;
+ }
+ }
+ errorf(expr->base.source_position, "second argument of 'va_start' must be last parameter of the current function");
+
+ return create_invalid_expression();
+}
+
+static expression_t *parse_va_arg(void)
+{
+ eat(T___builtin_va_arg);
+
+ expression_t *expression = allocate_expression_zero(EXPR_VA_ARG);
+
+ expect('(');
+ expression->va_arge.ap = parse_assignment_expression();
+ expect(',');
+ expression->base.datatype = parse_typename();
+ expect(')');
+
+ return expression;
+}
+
+static expression_t *parse_builtin_symbol(void)
+{
+ expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_SYMBOL);
+
+ symbol_t *symbol = token.v.symbol;
+
+ expression->builtin_symbol.symbol = symbol;
+ next_token();
+
+ type_t *type = get_builtin_symbol_type(symbol);
+ type = automatic_type_conversion(type);
+
+ expression->base.datatype = type;
+ return expression;
+}
+
+static expression_t *parse_builtin_constant(void)
+{
+ eat(T___builtin_constant_p);
+
+ expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_CONSTANT_P);
+
+ expect('(');
+ expression->builtin_constant.value = parse_assignment_expression();
+ expect(')');
+ expression->base.datatype = type_int;
+
+ return expression;
+}
+
+static expression_t *parse_builtin_prefetch(void)
+{
+ eat(T___builtin_prefetch);
+
+ expression_t *expression = allocate_expression_zero(EXPR_BUILTIN_PREFETCH);
+
+ expect('(');
+ expression->builtin_prefetch.adr = parse_assignment_expression();
+ if (token.type == ',') {
+ next_token();
+ expression->builtin_prefetch.rw = parse_assignment_expression();
+ }
+ if (token.type == ',') {
+ next_token();
+ expression->builtin_prefetch.locality = parse_assignment_expression();
+ }
+ expect(')');
+ expression->base.datatype = type_void;
+
+ return expression;
+}
+
+static expression_t *parse_compare_builtin(void)
+{
+ expression_t *expression;
+
+ switch(token.type) {
+ case T___builtin_isgreater:
+ expression = allocate_expression_zero(EXPR_BINARY_ISGREATER);
+ break;
+ case T___builtin_isgreaterequal:
+ expression = allocate_expression_zero(EXPR_BINARY_ISGREATEREQUAL);
+ break;
+ case T___builtin_isless:
+ expression = allocate_expression_zero(EXPR_BINARY_ISLESS);
+ break;
+ case T___builtin_islessequal:
+ expression = allocate_expression_zero(EXPR_BINARY_ISLESSEQUAL);
+ break;
+ case T___builtin_islessgreater:
+ expression = allocate_expression_zero(EXPR_BINARY_ISLESSGREATER);
+ break;
+ case T___builtin_isunordered:
+ expression = allocate_expression_zero(EXPR_BINARY_ISUNORDERED);
+ break;
+ default:
+ panic("invalid compare builtin found");
+ break;
+ }
+ next_token();
+
+ expect('(');
+ expression->binary.left = parse_assignment_expression();
+ expect(',');
+ expression->binary.right = parse_assignment_expression();
+ expect(')');
+
+ type_t *orig_type_left = expression->binary.left->base.datatype;
+ type_t *orig_type_right = expression->binary.right->base.datatype;
+ if(orig_type_left == NULL || orig_type_right == NULL)
+ return expression;
+
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *type_right = skip_typeref(orig_type_right);
+ if(!is_type_floating(type_left) && !is_type_floating(type_right)) {
+ type_error_incompatible("invalid operands in comparison",
+ token.source_position, type_left, type_right);
+ } else {
+ semantic_comparison(&expression->binary);
+ }
+
+ return expression;
+}
+
+static expression_t *parse_builtin_expect(void)
+{
+ eat(T___builtin_expect);
+
+ expression_t *expression
+ = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT);
+
+ expect('(');
+ expression->binary.left = parse_assignment_expression();
+ expect(',');
+ expression->binary.right = parse_constant_expression();
+ expect(')');
+
+ expression->base.datatype = expression->binary.left->base.datatype;
+
+ return expression;
+}
+
+static expression_t *parse_assume(void) {
+ eat(T_assume);
+
+ expression_t *expression
+ = allocate_expression_zero(EXPR_UNARY_ASSUME);
+
+ expect('(');
+ expression->unary.value = parse_assignment_expression();
+ expect(')');
+
+ expression->base.datatype = type_void;
+ return expression;
+}
+
+static expression_t *parse_alignof(void) {
+ eat(T___alignof__);
+
+ expression_t *expression
+ = allocate_expression_zero(EXPR_ALIGNOF);
+
+ expect('(');
+ expression->alignofe.type = parse_typename();
+ expect(')');
+
+ expression->base.datatype = type_size_t;
+ return expression;
+}
+
+static expression_t *parse_primary_expression(void)
+{
+ switch(token.type) {
+ case T_INTEGER:
+ return parse_int_const();
+ case T_FLOATINGPOINT:
+ return parse_float_const();
+ case T_STRING_LITERAL:
+ return parse_string_const();
+ case T_WIDE_STRING_LITERAL:
+ return parse_wide_string_const();
+ case T_IDENTIFIER:
+ return parse_reference();
+ case T___FUNCTION__:
+ case T___func__:
+ return parse_function_keyword();
+ case T___PRETTY_FUNCTION__:
+ return parse_pretty_function_keyword();
+ case T___builtin_offsetof:
+ return parse_offsetof();
+ case T___builtin_va_start:
+ return parse_va_start();
+ case T___builtin_va_arg:
+ return parse_va_arg();
+ case T___builtin_expect:
+ return parse_builtin_expect();
+ case T___builtin_nanf:
+ case T___builtin_alloca:
+ case T___builtin_va_end:
+ return parse_builtin_symbol();
+ case T___builtin_isgreater:
+ case T___builtin_isgreaterequal:
+ case T___builtin_isless:
+ case T___builtin_islessequal:
+ case T___builtin_islessgreater:
+ case T___builtin_isunordered:
+ return parse_compare_builtin();
+ case T___builtin_constant_p:
+ return parse_builtin_constant();
+ case T___builtin_prefetch:
+ return parse_builtin_prefetch();
+ case T___alignof__:
+ return parse_alignof();
+ case T_assume:
+ return parse_assume();
+
+ case '(':
+ return parse_brace_expression();
+ }
+
+ errorf(HERE, "unexpected token '%K'", &token);
+ eat_statement();
+
+ return create_invalid_expression();
+}
+
+/**
+ * Check if the expression has the character type and issue a warning then.
+ */
+static void check_for_char_index_type(const expression_t *expression) {
+ type_t *type = expression->base.datatype;
+ type_t *base_type = skip_typeref(type);
+
+ if (base_type->base.kind == TYPE_ATOMIC) {
+ if (base_type->atomic.akind == ATOMIC_TYPE_CHAR) {
+ warningf(expression->base.source_position,
+ "array subscript has type '%T'", type);
+ }
+ }
+}
+
+static expression_t *parse_array_expression(unsigned precedence,
+ expression_t *left)
+{
+ (void) precedence;
+
+ eat('[');
+
+ expression_t *inside = parse_expression();
+
+ array_access_expression_t *array_access
+ = allocate_ast_zero(sizeof(array_access[0]));
+
+ array_access->expression.kind = EXPR_ARRAY_ACCESS;
+
+ type_t *type_left = left->base.datatype;
+ type_t *type_inside = inside->base.datatype;
+ type_t *return_type = NULL;
+
+ if(type_left != NULL && type_inside != NULL) {
+ type_left = skip_typeref(type_left);
+ type_inside = skip_typeref(type_inside);
+
+ if(is_type_pointer(type_left)) {
+ pointer_type_t *pointer = &type_left->pointer;
+ return_type = pointer->points_to;
+ array_access->array_ref = left;
+ array_access->index = inside;
+ check_for_char_index_type(inside);
+ } else if(is_type_pointer(type_inside)) {
+ pointer_type_t *pointer = &type_inside->pointer;
+ return_type = pointer->points_to;
+ array_access->array_ref = inside;
+ array_access->index = left;
+ array_access->flipped = true;
+ check_for_char_index_type(left);
+ } else {
+ errorf(HERE, "array access on object with non-pointer types '%T', '%T'", type_left, type_inside);
+ }
+ } else {
+ array_access->array_ref = left;
+ array_access->index = inside;
+ }
+
+ if(token.type != ']') {
+ parse_error_expected("Problem while parsing array access", ']', 0);
+ return (expression_t*) array_access;
+ }
+ next_token();
+
+ return_type = automatic_type_conversion(return_type);
+ array_access->expression.datatype = return_type;
+
+ return (expression_t*) array_access;
+}
+
+static expression_t *parse_sizeof(unsigned precedence)
+{
+ eat(T_sizeof);