+ while(token.type == T_STRING_LITERAL) {
+ result = concat_strings(result, token.v.string);
+ next_token();
+ }
+
+ return result;
+}
+
+static void parse_attributes(void)
+{
+ while(true) {
+ switch(token.type) {
+ case T___attribute__:
+ next_token();
+
+ expect_void('(');
+ int depth = 1;
+ while(depth > 0) {
+ switch(token.type) {
+ case T_EOF:
+ parse_error("EOF while parsing attribute");
+ break;
+ case '(':
+ next_token();
+ depth++;
+ break;
+ case ')':
+ next_token();
+ depth--;
+ break;
+ default:
+ next_token();
+ }
+ }
+ break;
+ case T_asm:
+ next_token();
+ expect_void('(');
+ if(token.type != T_STRING_LITERAL) {
+ parse_error_expected("while parsing assembler attribute",
+ T_STRING_LITERAL);
+ eat_brace();
+ break;
+ } else {
+ parse_string_literals();
+ }
+ expect_void(')');
+ break;
+ default:
+ goto attributes_finished;
+ }
+ }
+
+attributes_finished:
+ ;
+}
+
+static designator_t *parse_designation(void)
+{
+ if(token.type != '[' && token.type != '.')
+ return NULL;
+
+ designator_t *result = NULL;
+ designator_t *last = NULL;
+
+ while(1) {
+ designator_t *designator;
+ switch(token.type) {
+ case '[':
+ designator = allocate_ast_zero(sizeof(designator[0]));
+ next_token();
+ designator->array_access = parse_constant_expression();
+ expect(']');
+ break;
+ case '.':
+ designator = allocate_ast_zero(sizeof(designator[0]));
+ next_token();
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("problem while parsing designator",
+ T_IDENTIFIER, 0);
+ return NULL;
+ }
+ designator->symbol = token.v.symbol;
+ next_token();
+ break;
+ default:
+ expect('=');
+ return result;
+ }
+
+ assert(designator != NULL);
+ if(last != NULL) {
+ last->next = designator;
+ } else {
+ result = designator;
+ }
+ last = designator;
+ }
+}
+
+static initializer_t *parse_initializer_list(void);
+
+static initializer_t *parse_initializer(void)
+{
+ designator_t *designator = parse_designation();
+
+ initializer_t *result;
+ if(token.type == '{') {
+ result = parse_initializer_list();
+ } else {
+ result = allocate_ast_zero(sizeof(result[0]));
+ result->type = INITIALIZER_VALUE;
+ result->v.value = parse_assignment_expression();
+ }
+ result->designator = designator;
+
+ return result;
+}
+
+static initializer_t *parse_initializer_list(void)
+{
+ eat('{');
+
+ initializer_t *result = allocate_ast_zero(sizeof(result[0]));
+ result->type = INITIALIZER_LIST;
+
+ initializer_t *last = NULL;
+ while(1) {
+ initializer_t *initializer = parse_initializer();
+ if(last != NULL) {
+ last->next = initializer;
+ } else {
+ result->v.list = initializer;
+ }
+ last = initializer;
+
+ if(token.type == '}')
+ break;
+
+ if(token.type != ',') {
+ parse_error_expected("problem while parsing initializer list",
+ ',', '}', 0);
+ eat_block();
+ return result;
+ }
+ eat(',');
+
+ if(token.type == '}')
+ break;
+ }
+
+ expect('}');
+
+ return result;
+}
+
+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_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("problem while parsing struct type specifier",
+ T_IDENTIFIER, '{', 0);
+ } else {
+ parse_error_expected("problem while parsing union type specifier",
+ T_IDENTIFIER, '{', 0);
+ }
+
+ return NULL;
+ }
+
+ if(declaration == NULL) {
+ declaration = allocate_type_zero(sizeof(declaration[0]));
+
+ if(is_struct) {
+ declaration->namespace = NAMESPACE_STRUCT;
+ } else {
+ declaration->namespace = NAMESPACE_UNION;
+ }
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ }
+
+ if(token.type == '{') {
+ if(declaration->init.is_defined) {
+ assert(symbol != NULL);
+ parser_print_error_prefix();
+ fprintf(stderr, "multiple definition of %s %s\n",
+ is_struct ? "struct" : "union", symbol->string);
+ declaration->context.declarations = NULL;
+ }
+ record_declaration(declaration);
+ 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(void)
+{
+ eat('{');
+
+ if(token.type == '}') {
+ next_token();
+ parse_error("empty enum not allowed");
+ return;
+ }
+
+ do {
+ declaration_t *entry = allocate_ast_zero(sizeof(entry[0]));
+
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("problem while parsing enum entry",
+ T_IDENTIFIER, 0);
+ eat_block();
+ return;
+ }
+ entry->storage_class = STORAGE_CLASS_ENUM_ENTRY;
+ entry->symbol = token.v.symbol;
+ entry->source_position = token.source_position;
+ next_token();
+
+ if(token.type == '=') {
+ next_token();
+ entry->init.initializer = parse_initializer();
+ }
+
+ record_declaration(entry);
+
+ if(token.type != ',')
+ break;
+ next_token();
+ } while(token.type != '}');
+
+ expect_void('}');
+}
+
+static declaration_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("problem while parsing enum type specifier",
+ T_IDENTIFIER, '{', 0);
+ return NULL;
+ } else {
+ declaration = NULL;
+ symbol = NULL;
+ }
+
+ if(declaration == NULL) {
+ declaration = allocate_type_zero(sizeof(declaration[0]));
+
+ declaration->namespace = NAMESPACE_ENUM;
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ }
+
+ if(token.type == '{') {
+ if(declaration->init.is_defined) {
+ parser_print_error_prefix();
+ fprintf(stderr, "multiple definitions of enum %s\n",
+ symbol->string);
+ }
+ record_declaration(declaration);
+ declaration->init.is_defined = 1;
+
+ parse_enum_entries();
+ parse_attributes();
+ }
+
+ return declaration;
+}
+
+/**
+ * if a symbol is a typedef to another type, return true
+ */
+static bool is_typedef_symbol(symbol_t *symbol)
+{
+ declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL);
+ if(declaration == NULL
+ || declaration->storage_class != STORAGE_CLASS_TYPEDEF)
+ return false;
+
+ return true;
+}
+
+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->datatype;
+ }
+ break;
+
+ TYPENAME_START
+ type = parse_typename();
+ break;
+
+ default:
+ expression = parse_expression();
+ type = expression->datatype;
+ break;
+ }
+
+ expect(')');
+
+ typeof_type_t *typeof = allocate_type_zero(sizeof(typeof[0]));
+ typeof->type.type = TYPE_TYPEOF;
+ typeof->expression = expression;
+ typeof->typeof_type = type;
+
+ return (type_t*) typeof;
+}
+
+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,
+#endif
+#ifdef PROVIDE_IMAGINARY
+ SPECIFIER_IMAGINARY = 1 << 12,
+#endif
+} specifiers_t;
+
+static type_t *create_builtin_type(symbol_t *symbol)
+{
+ builtin_type_t *type = allocate_type_zero(sizeof(type[0]));
+ type->type.type = TYPE_BUILTIN;
+ type->symbol = symbol;
+
+ return (type_t*) type;
+}
+
+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;
+
+ typedef_type_t *typedef_type = allocate_type_zero(sizeof(typedef_type[0]));
+ typedef_type->type.type = TYPE_TYPEDEF;
+ typedef_type->declaration = declaration;
+
+ return (type_t*) typedef_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;
+
+ while(true) {
+ switch(token.type) {
+
+ /* storage class */
+#define MATCH_STORAGE_CLASS(token, class) \
+ case token: \