+
+ 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.type = 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();
+ return initializer_from_expression(type, expression);
+ }
+
+ 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 *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_type_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;
+ record_declaration(declaration);
+ }
+
+ 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;
+ }
+ 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(type_t *enum_type)
+{
+ 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("while parsing enum entry", T_IDENTIFIER, 0);
+ eat_block();
+ return;
+ }
+ entry->storage_class = STORAGE_CLASS_ENUM_ENTRY;
+ entry->type = 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 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("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->namespc = 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(NULL);
+ parse_attributes();
+ }
+
+ return declaration;
+}
+
+/**
+ * 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->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,
+ 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;
+ /* TODO... */
+ type->real_type = type_int;
+
+ 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: \
+ if(specifiers->storage_class != STORAGE_CLASS_NONE) { \
+ parse_error("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)
+
+ /* 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) { \
+ parse_error("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_inline:
+ next_token();
+ specifiers->is_inline = true;
+ break;
+
+ case T_long:
+ next_token();
+ if(type_specifiers & SPECIFIER_LONG_LONG) {
+ parse_error("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: {
+ compound_type_t *compound_type
+ = allocate_type_zero(sizeof(compound_type[0]));
+ compound_type->type.type = TYPE_COMPOUND_STRUCT;
+ compound_type->declaration = parse_compound_type_specifier(true);
+
+ type = (type_t*) compound_type;
+ break;
+ }
+ case T_union: {
+ compound_type_t *compound_type
+ = allocate_type_zero(sizeof(compound_type[0]));
+ compound_type->type.type = TYPE_COMPOUND_UNION;
+ compound_type->declaration = parse_compound_type_specifier(false);
+
+ type = (type_t*) compound_type;
+ break;
+ }
+ case T_enum: {
+ enum_type_t *enum_type = allocate_type_zero(sizeof(enum_type[0]));
+ enum_type->type.type = TYPE_ENUM;
+ enum_type->declaration = parse_enum_specifier();
+
+ type = (type_t*) enum_type;
+ break;
+ }
+ case T___typeof__:
+ type = parse_typeof();
+ break;
+ case T___builtin_va_list:
+ type = create_builtin_type(token.v.symbol);
+ 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_type_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) {
+#ifndef STRICT_C99
+ parse_warning("no type specifiers in declaration (using int)");
+ atomic_type = ATOMIC_TYPE_INT;
+ break;
+#else
+ parse_error("no type specifiers given in declaration");
+#endif
+ } else if((type_specifiers & SPECIFIER_SIGNED) &&
+ (type_specifiers & SPECIFIER_UNSIGNED)) {
+ parse_error("signed and unsigned specifiers gives");
+ } else if(type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) {
+ parse_error("only integer types can be signed or unsigned");
+ } else {
+ parse_error("multiple datatypes in declaration");
+ }
+ atomic_type = ATOMIC_TYPE_INVALID;
+ }
+
+ atomic_type_t *atype = allocate_type_zero(sizeof(atype[0]));
+ atype->type.type = TYPE_ATOMIC;
+ atype->atype = atomic_type;
+ newtype = 1;
+
+ type = (type_t*) atype;
+ } else {
+ if(type_specifiers != 0) {
+ parse_error("multiple datatypes in declaration");
+ }
+ }
+
+ type->qualifiers = (type_qualifier_t)type_qualifiers;
+
+ type_t *result = typehash_insert(type);
+ if(newtype && result != (type_t*) type) {
+ free_type(type);
+ }
+
+ specifiers->type = result;
+}
+
+static unsigned parse_type_qualifiers(void)
+{
+ unsigned 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 void parse_identifier_list(void)
+{
+ while(true) {
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing parameter identifier list",
+ T_IDENTIFIER, 0);
+ return;
+ }
+ next_token();
+ if(token.type != ',')
+ break;
+ next_token();
+ }
+}
+
+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, specifiers.type, true);
+
+ /* TODO check declaration constraints for parameters */
+ if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
+ parse_error("typedef not allowed in parameter list");
+ }
+
+ /* Array as last part of a paramter type is just syntactic sugar. Turn it
+ * into a pointer */
+ if (declaration->type->type == TYPE_ARRAY) {
+ const array_type_t *const arr_type =
+ (const array_type_t*)declaration->type;
+ declaration->type =
+ make_pointer_type(arr_type->element_type, TYPE_QUALIFIER_NONE);
+ }
+
+ 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)) {
+ /* TODO: K&R style C parameters */
+ parse_identifier_list();
+ return NULL;
+ }
+ }
+
+ 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 = allocate_type_zero(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_qualifier_t type_qualifiers;
+};
+
+typedef struct construct_function_type_t construct_function_type_t;
+struct construct_function_type_t {
+ construct_type_t construct_type;
+ function_type_t *function_type;
+};
+
+typedef struct parsed_array_t parsed_array_t;
+struct parsed_array_t {
+ construct_type_t construct_type;
+ type_qualifier_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_qualifier_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('(');
+
+ function_type_t *type = allocate_type_zero(sizeof(type[0]));
+ type->type.type = TYPE_FUNCTION;
+
+ declaration_t *parameters = parse_parameters(type);
+ 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) {
+ parse_error("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) {
+ parsed_pointer_t *parsed_pointer;
+ parsed_array_t *parsed_array;
+ construct_function_type_t *construct_function_type;
+ function_type_t *function_type;
+ pointer_type_t *pointer_type;
+ array_type_t *array_type;
+
+ switch(iter->type) {
+ case CONSTRUCT_INVALID:
+ panic("invalid type construction found");
+ case CONSTRUCT_FUNCTION:
+ construct_function_type = (construct_function_type_t*) iter;
+ function_type = construct_function_type->function_type;
+
+ function_type->result_type = type;
+ type = (type_t*) function_type;
+ break;
+
+ case CONSTRUCT_POINTER:
+ parsed_pointer = (parsed_pointer_t*) iter;
+ pointer_type = allocate_type_zero(sizeof(pointer_type[0]));
+
+ pointer_type->type.type = TYPE_POINTER;
+ pointer_type->points_to = type;
+ pointer_type->type.qualifiers = parsed_pointer->type_qualifiers;
+ type = (type_t*) pointer_type;
+ break;
+
+ case CONSTRUCT_ARRAY:
+ parsed_array = (parsed_array_t*) iter;
+ array_type = allocate_type_zero(sizeof(array_type[0]));
+
+ array_type->type.type = TYPE_ARRAY;
+ array_type->element_type = type;
+ array_type->type.qualifiers = parsed_array->type_qualifiers;
+ array_type->is_static = parsed_array->is_static;
+ array_type->is_variable = parsed_array->is_variable;
+ array_type->size = parsed_array->size;
+ type = (type_t*) array_type;
+ break;
+ }
+
+ type_t *hashed_type = typehash_insert((type_t*) 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,
+ type_t *type, bool may_be_abstract)
+{
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration->storage_class = specifiers->storage_class;
+ 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 *record_declaration(declaration_t *declaration)
+{
+ assert(context != NULL);
+
+ symbol_t *symbol = declaration->symbol;
+ if(symbol != NULL) {
+ declaration_t *alias = environment_push(declaration);
+ if(alias != declaration)
+ return alias;
+ } else {
+ declaration->parent_context = context;
+ }
+
+ if(last_declaration != NULL) {
+ last_declaration->next = declaration;
+ } else {
+ context->declarations = declaration;
+ }
+ last_declaration = declaration;
+
+ return declaration;
+}
+
+static void parser_error_multiple_definition(declaration_t *previous,
+ declaration_t *declaration)
+{
+ parser_print_error_prefix_pos(declaration->source_position);
+ fprintf(stderr, "multiple definition of symbol '%s'\n",
+ declaration->symbol->string);
+ parser_print_error_prefix_pos(previous->source_position);
+ fprintf(stderr, "this is the location of the previous definition.\n");
+}
+
+static void parse_init_declarators(const declaration_specifiers_t *specifiers)
+{
+ while(true) {
+ declaration_t *ndeclaration
+ = parse_declarator(specifiers, specifiers->type, false);
+
+ declaration_t *declaration = record_declaration(ndeclaration);
+
+ type_t *orig_type = declaration->type;
+ type_t *type = skip_typeref(orig_type);
+ if(type->type != TYPE_FUNCTION && declaration->is_inline) {
+ parser_print_warning_prefix_pos(declaration->source_position);
+ fprintf(stderr, "variable '%s' declared 'inline'\n",
+ declaration->symbol->string);
+ }
+
+ if(token.type == '=') {
+ next_token();
+
+ /* TODO: check that this is an allowed type (no function type) */
+
+ if(declaration->init.initializer != NULL) {
+ parser_error_multiple_definition(declaration, ndeclaration);
+ }
+
+ initializer_t *initializer = parse_initializer(type);
+
+ if(type->type == TYPE_ARRAY && initializer != NULL) {
+ array_type_t *array_type = (array_type_t*) type;
+
+ if(array_type->size == NULL) {
+ const_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
+
+ cnst->expression.type = EXPR_CONST;
+ cnst->expression.datatype = type_size_t;
+
+ if(initializer->type == INITIALIZER_LIST) {
+ initializer_list_t *list
+ = (initializer_list_t*) initializer;
+ cnst->v.int_value = list->len;
+ } else {
+ assert(initializer->type == INITIALIZER_STRING);
+ initializer_string_t *string
+ = (initializer_string_t*) initializer;
+ cnst->v.int_value = strlen(string->string) + 1;
+ }
+
+ array_type->size = (expression_t*) cnst;
+ }
+ }
+
+
+ ndeclaration->init.initializer = initializer;
+ } else if(token.type == '{') {
+ if(type->type != TYPE_FUNCTION) {
+ parser_print_error_prefix();
+ fprintf(stderr, "declarator '");
+ print_type_ext(orig_type, declaration->symbol, NULL);
+ fprintf(stderr, "' has a body but is not a function type.\n");
+ eat_block();
+ continue;
+ }
+
+ if(declaration->init.statement != NULL) {
+ parser_error_multiple_definition(declaration, ndeclaration);
+ }
+ if(ndeclaration != declaration) {
+ memcpy(&declaration->context, &ndeclaration->context,
+ sizeof(declaration->context));
+ }
+
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
+
+ /* push function parameters */
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ environment_push(parameter);
+ }
+
+ int label_stack_top = label_top();
+ declaration_t *old_current_function = current_function;
+ current_function = declaration;
+
+ statement_t *statement = parse_compound_statement();
+
+ assert(current_function == declaration);
+ current_function = old_current_function;
+ label_pop_to(label_stack_top);
+
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
+
+ declaration->init.statement = statement;
+ return;
+ }
+
+ if(token.type != ',')
+ break;
+ next_token();
+ }
+ expect_void(';');
+}
+
+static void parse_struct_declarators(const declaration_specifiers_t *specifiers)
+{
+ while(1) {
+ if(token.type == ':') {
+ next_token();
+ parse_constant_expression();
+ /* TODO (bitfields) */
+ } else {
+ declaration_t *declaration
+ = parse_declarator(specifiers, specifiers->type, true);
+
+ /* TODO: check constraints for struct declarations */
+ /* TODO: check for doubled fields */
+ record_declaration(declaration);
+
+ if(token.type == ':') {
+ next_token();
+ parse_constant_expression();
+ /* TODO (bitfields) */
+ }
+ }
+
+ 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) {
+ parse_error("unexpected error while parsing struct");
+ }
+ next_token();
+}
+
+static void parse_declaration(void)
+{
+ source_position_t source_position = token.source_position;
+
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
+
+ if(token.type == ';') {
+ if (specifiers.storage_class != STORAGE_CLASS_NONE) {
+ parse_warning_pos(source_position,
+ "useless keyword in empty declaration");
+ }
+ switch (specifiers.type->type) {
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: {
+ const compound_type_t *const comp_type =
+ (const compound_type_t*)specifiers.type;
+ if (comp_type->declaration->symbol == NULL) {
+ parse_warning_pos(source_position,
+ "unnamed struct/union that defines no instances");
+ }
+ break;
+ }
+
+ case TYPE_ENUM: break;
+
+ default:
+ parse_warning_pos(source_position, "empty declaration");
+ break;
+ }
+
+ next_token();
+
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+
+ declaration->type = specifiers.type;
+ declaration->storage_class = specifiers.storage_class;
+ declaration->source_position = source_position;
+ record_declaration(declaration);
+ return;
+ }
+ parse_init_declarators(&specifiers);
+}
+
+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...
+ */
+ parse_error("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];
+
+static expression_t *make_invalid_expression(void)
+{
+ expression_t *expression = allocate_ast_zero(sizeof(expression[0]));
+ expression->type = EXPR_INVALID;
+ expression->source_position = token.source_position;
+ return expression;
+}
+
+static expression_t *expected_expression_error(void)
+{
+ parser_print_error_prefix();
+ fprintf(stderr, "expected expression, got token ");
+ print_token(stderr, & token);
+ fprintf(stderr, "\n");
+
+ next_token();
+
+ return make_invalid_expression();
+}
+
+static expression_t *parse_string_const(void)
+{
+ string_literal_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
+
+ cnst->expression.type = EXPR_STRING_LITERAL;
+ cnst->expression.datatype = type_string;
+ cnst->value = parse_string_literals();
+
+ return (expression_t*) cnst;
+}
+
+static expression_t *parse_int_const(void)
+{
+ const_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
+
+ cnst->expression.type = EXPR_CONST;
+ cnst->expression.datatype = token.datatype;
+ cnst->v.int_value = token.v.intvalue;
+
+ next_token();
+
+ return (expression_t*) cnst;
+}
+
+static expression_t *parse_float_const(void)
+{
+ const_t *cnst = allocate_ast_zero(sizeof(cnst[0]));
+
+ cnst->expression.type = EXPR_CONST;
+ cnst->expression.datatype = token.datatype;
+ cnst->v.float_value = token.v.floatvalue;
+
+ next_token();
+
+ return (expression_t*) cnst;
+}
+
+static declaration_t *create_implicit_function(symbol_t *symbol,
+ const source_position_t source_position)
+{
+ function_type_t *function_type
+ = allocate_type_zero(sizeof(function_type[0]));
+
+ function_type->type.type = TYPE_FUNCTION;
+ function_type->result_type = type_int;
+ function_type->unspecified_parameters = true;
+
+ type_t *type = typehash_insert((type_t*) function_type);
+ if(type != (type_t*) function_type) {
+ free_type(function_type);
+ }
+
+ 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;
+
+ /* prepend the implicit definition to the global context
+ * this is safe since the symbol wasn't declared as anything else yet
+ */
+ assert(symbol->declaration == NULL);
+
+ context_t *last_context = context;
+ context = global_context;
+
+ environment_push(declaration);
+ declaration->next = context->declarations;
+ context->declarations = declaration;
+
+ context = last_context;
+
+ return declaration;
+}
+
+static expression_t *parse_reference(void)
+{
+ reference_expression_t *ref = allocate_ast_zero(sizeof(ref[0]));
+
+ ref->expression.type = EXPR_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) {
+#ifndef STRICT_C99
+ /* an implicitly defined function */
+ if(token.type == '(') {
+ parser_print_prefix_pos(token.source_position);
+ fprintf(stderr, "warning: implicit declaration of function '%s'\n",
+ ref->symbol->string);
+
+ declaration = create_implicit_function(ref->symbol,
+ source_position);
+ } else
+#endif
+ {
+ parser_print_error_prefix();
+ fprintf(stderr, "unknown symbol '%s' found.\n", ref->symbol->string);
+ return (expression_t*) ref;
+ }
+ }
+
+ ref->declaration = declaration;
+ ref->expression.datatype = declaration->type;
+
+ return (expression_t*) ref;
+}
+
+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)
+{
+ unary_expression_t *cast = allocate_ast_zero(sizeof(cast[0]));
+
+ cast->expression.type = EXPR_UNARY;
+ cast->type = UNEXPR_CAST;
+ cast->expression.source_position = token.source_position;
+
+ type_t *type = parse_typename();
+
+ expect(')');
+ expression_t *value = parse_sub_expression(20);
+
+ check_cast_allowed(value, type);
+
+ cast->expression.datatype = type;
+ cast->value = value;
+
+ return (expression_t*) cast;
+}
+
+static expression_t *parse_statement_expression(void)
+{
+ statement_expression_t *expression
+ = allocate_ast_zero(sizeof(expression[0]));
+ expression->expression.type = EXPR_STATEMENT;
+
+ statement_t *statement = parse_compound_statement();
+ expression->statement = statement;
+ if(statement == NULL) {
+ expect(')');
+ return NULL;
+ }
+
+ assert(statement->type == STATEMENT_COMPOUND);
+ compound_statement_t *compound_statement
+ = (compound_statement_t*) statement;
+
+ /* 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->next) {
+ last_statement = iter;
+ }
+
+ if(last_statement->type == STATEMENT_EXPRESSION) {
+ const expression_statement_t *expression_statement =
+ (const expression_statement_t*) last_statement;
+ expression->expression.datatype
+ = expression_statement->expression->datatype;
+ } else {
+ expression->expression.datatype = type_void;
+ }
+
+ expect(')');
+
+ return (expression_t*) expression;
+}
+
+static expression_t *parse_brace_expression(void)
+{
+ eat('(');
+
+ switch(token.type) {
+ case '{':
+ /* gcc extension: a stement 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) {
+ parse_error("'__func__' used outside of a function");
+ }
+
+ string_literal_t *expression = allocate_ast_zero(sizeof(expression[0]));
+ expression->expression.type = EXPR_FUNCTION;
+ expression->expression.datatype = type_string;
+ expression->value = "TODO: FUNCTION";
+
+ return (expression_t*) expression;
+}
+
+static expression_t *parse_pretty_function_keyword(void)
+{
+ eat(T___PRETTY_FUNCTION__);
+ /* TODO */
+
+ string_literal_t *expression = allocate_ast_zero(sizeof(expression[0]));
+ expression->expression.type = EXPR_PRETTY_FUNCTION;
+ expression->expression.datatype = type_string;
+ expression->value = "TODO: PRETTY FUNCTION";
+
+ 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_brace();
+ 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_brace();
+ 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_brace();
+ return NULL;
+ }
+ expect(']');
+
+ last_designator->next = designator;
+ last_designator = designator;
+ continue;
+ }
+ break;
+ }
+
+ return result;
+}
+
+static expression_t *parse_offsetof(void)
+{
+ eat(T___builtin_offsetof);
+
+ offsetof_expression_t *expression
+ = allocate_ast_zero(sizeof(expression[0]));
+ expression->expression.type = EXPR_OFFSETOF;
+ expression->expression.datatype = type_size_t;
+
+ expect('(');
+ expression->type = parse_typename();
+ expect(',');
+ expression->designator = parse_designator();
+ expect(')');
+
+ return (expression_t*) expression;
+}
+
+static expression_t *parse_va_arg(void)
+{
+ eat(T___builtin_va_arg);
+
+ va_arg_expression_t *expression = allocate_ast_zero(sizeof(expression[0]));
+ expression->expression.type = EXPR_VA_ARG;
+
+ expect('(');
+ expression->arg = parse_assignment_expression();
+ expect(',');
+ expression->expression.datatype = parse_typename();
+ expect(')');
+
+ return (expression_t*) expression;