+static void set_context(context_t *new_context)
+{
+ context = new_context;
+
+ declaration_t *declaration = new_context->declarations;
+ if(declaration != NULL) {
+ while(1) {
+ if(declaration->next == NULL)
+ break;
+ declaration = declaration->next;
+ }
+ }
+
+ last_declaration = declaration;
+}
+
+/**
+ * called when we find a 2nd declarator for an identifier we already have a
+ * declarator for
+ */
+static int is_compatible_declaration (declaration_t *declaration,
+ declaration_t *previous)
+{
+ /* TODO: not correct yet */
+ return declaration->type == previous->type;
+}
+
+/**
+ * pushs an environment_entry on the environment stack and links the
+ * corresponding symbol to the new entry
+ */
+static inline
+declaration_t *environment_push(declaration_t *declaration, const void *context)
+{
+ environment_entry_t *entry
+ = obstack_alloc(&environment_obstack, sizeof(entry[0]));
+ memset(entry, 0, sizeof(entry[0]));
+
+ int top = ARR_LEN(environment_stack);
+ ARR_RESIZE(environment_stack, top + 1);
+ environment_stack[top] = entry;
+
+ assert(declaration->source_position.input_name != NULL);
+
+ symbol_t *symbol = declaration->symbol;
+ assert(declaration != symbol->declaration);
+
+ if(symbol->context == context) {
+ declaration_t *previous_declaration = symbol->declaration;
+ if(symbol->declaration != NULL) {
+ if(!is_compatible_declaration(declaration, previous_declaration)) {
+ parser_print_error_prefix_pos(declaration->source_position);
+ fprintf(stderr, "definition of symbol '%s' with type ",
+ declaration->symbol->string);
+ print_type(declaration->type, NULL);
+ fputc('\n', stderr);
+ parser_print_error_prefix_pos(
+ previous_declaration->source_position);
+ fprintf(stderr, "is incompatible with previous declaration "
+ "of type ");
+ print_type(previous_declaration->type, NULL);
+ fputc('\n', stderr);
+ }
+ return previous_declaration;
+ }
+ }
+
+ entry->old_declaration = symbol->declaration;
+ entry->old_context = symbol->context;
+ entry->symbol = symbol;
+ symbol->declaration = declaration;
+ symbol->context = context;
+
+ return declaration;
+}
+
+/**
+ * pops symbols from the environment stack until @p new_top is the top element
+ */
+static inline
+void environment_pop_to(size_t new_top)
+{
+ environment_entry_t *entry = NULL;
+ size_t top = ARR_LEN(environment_stack);
+ size_t i;
+
+ if(new_top == top)
+ return;
+
+ assert(new_top < top);
+ i = top;
+ do {
+ entry = environment_stack[i - 1];
+
+ symbol_t *symbol = entry->symbol;
+
+ symbol->declaration = entry->old_declaration;
+ symbol->context = entry->old_context;
+
+ --i;
+ } while(i != new_top);
+ obstack_free(&environment_obstack, entry);
+
+ ARR_SHRINKLEN(environment_stack, (int) new_top);
+}
+
+
+
+static expression_t *parse_constant_expression(void)
+{
+ /* TODO: not correct yet */
+ return parse_expression();
+}
+
+static expression_t *parse_assignment_expression(void)
+{
+ /* TODO: not correct yet */
+ return parse_expression();
+}
+
+static void parse_compound_type_entries(void);
+static void parse_declarator(declaration_t *declaration,
+ storage_class_t storage_class, type_t *type,
+ int may_be_abstract);
+static declaration_t *record_declaration(declaration_t *declaration);
+
+typedef struct declaration_specifiers_t declaration_specifiers_t;
+struct declaration_specifiers_t {
+ storage_class_t storage_class;
+ type_t *type;
+};
+
+static compound_type_t *find_compound_type(compound_type_t *types,
+ const symbol_t *symbol)
+{
+ compound_type_t *type = types;
+ for( ; type != NULL; type = type->next) {
+ if(type->symbol == symbol)
+ return type;
+ }
+
+ return NULL;
+}
+
+static type_t *parse_compound_type_specifier(int is_struct)
+{
+ if(is_struct) {
+ eat(T_struct);
+ } else {
+ eat(T_union);
+ }
+
+ symbol_t *symbol = NULL;
+ compound_type_t *compound_type = NULL;
+
+ if(token.type == T_IDENTIFIER) {
+ symbol = token.v.symbol;
+ next_token();
+
+ if(context != NULL) {
+ if(is_struct) {
+ compound_type = find_compound_type(context->structs, symbol);
+ } else {
+ compound_type = find_compound_type(context->unions, symbol);
+ }
+ }
+ } else if(token.type != '{') {
+ if(is_struct) {
+ parse_error_expected("problem while parsing struct type specifiers",
+ T_IDENTIFIER, '{', 0);
+ } else {
+ parse_error_expected("problem while parsing union type specifiers",
+ T_IDENTIFIER, '{', 0);
+ }
+
+ return NULL;
+ }
+
+ if(compound_type == NULL) {
+ compound_type = allocate_type_zero(sizeof(compound_type[0]));
+
+ if(is_struct) {
+ compound_type->type.type = TYPE_COMPOUND_STRUCT;
+ } else {
+ compound_type->type.type = TYPE_COMPOUND_UNION;
+ }
+ compound_type->source_position = token.source_position;
+ compound_type->symbol = symbol;
+ }
+
+ if(token.type == '{') {
+ if(compound_type->defined) {
+ parser_print_error_prefix();
+ fprintf(stderr, "multiple definition of %s %s\n",
+ is_struct ? "struct" : "union", symbol->string);
+ compound_type->context.declarations = NULL;
+ }
+ compound_type->defined = 1;
+
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&compound_type->context);
+
+ parse_compound_type_entries();
+
+ assert(context == &compound_type->context);
+ set_context(last_context);
+ environment_pop_to(top);
+ }
+
+ return (type_t*) compound_type;
+}
+
+static enum_entry_t *parse_enum_type_entries(void)
+{
+ eat('{');
+
+ if(token.type == '}') {
+ next_token();
+ parse_error("empty enum not allowed");
+ return NULL;
+ }
+
+ enum_entry_t *result = NULL;
+ enum_entry_t *last_entry = NULL;
+ do {
+ enum_entry_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 result;
+ }
+ entry->symbol = token.v.symbol;
+ next_token();
+
+ if(token.type == '=') {
+ next_token();
+ entry->value = parse_constant_expression();
+ }
+
+ if(last_entry != NULL) {
+ last_entry->next = entry;
+ } else {
+ result = entry;
+ }
+ last_entry = entry;
+
+ if(token.type != ',')
+ break;
+ next_token();
+ } while(token.type != '}');
+
+ expect('}');
+ return result;
+}
+
+static type_t *parse_enum_specifier(void)
+{
+ eat(T_enum);
+
+ enum_type_t *enum_type = allocate_type_zero(sizeof(enum_type[0]));
+ enum_type->type.type = TYPE_ENUM;
+ enum_type->source_position = token.source_position;
+
+ /* TODO: rewrite to the same style as struct/union above to handle
+ * type identities correctly
+ */
+
+ if(token.type == T_IDENTIFIER) {
+ enum_type->symbol = token.v.symbol;
+ next_token();
+ if(token.type == '{') {
+ enum_type->entries = parse_enum_type_entries();
+ }
+ } else if(token.type == '{') {
+ enum_type->entries = parse_enum_type_entries();
+ } else {
+ parse_error_expected("problem while parsing enum type specifiers",
+ T_IDENTIFIER, '{');
+ }
+
+ return (type_t*) enum_type;
+}
+
+static
+const char *parse_string_literals(void)
+{
+ assert(token.type == T_STRING_LITERAL);
+ const char *result = token.v.string;
+
+ next_token();
+
+ while(token.type == T_STRING_LITERAL) {
+ result = concat_strings(result, token.v.string);
+ next_token();
+ }
+
+ return result;
+}
+
+static
+void parse_attributes(void)
+{
+ while(1) {
+ 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:
+ ;
+}