+ declaration->init.statement = parse_compound_statement();
+ check_for_missing_labels();
+
+ 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_declaration_zero();
+ declaration->namespc = NAMESPACE_NORMAL;
+ declaration->storage_class = STORAGE_CLASS_NONE;
+ declaration->source_position = token.source_position;
+ declaration->modifiers = specifiers->decl_modifiers;
+ declaration->type = type;
+ } 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;
+}
+
+/**
+ * Prints an error message if an expression was expected but not read
+ */
+static expression_t *expected_expression_error(void)
+{
+ /* skip the error message if the error token was read */
+ if (token.type != T_ERROR) {
+ 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 *const declaration = allocate_declaration_zero();
+ 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 */