unsigned short namespc;
} stack_entry_t;
+typedef struct declaration_specifiers_t declaration_specifiers_t;
+struct declaration_specifiers_t {
+ source_position_t source_position;
+ unsigned char storage_class;
+ bool is_inline;
+ type_t *type;
+};
+
+typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration);
+
static token_t token;
static token_t lookahead_buffer[MAX_LOOKAHEAD];
static int lookahead_bufpos;
static type_t *type_string = NULL;
static type_t *type_void = NULL;
static type_t *type_void_ptr = NULL;
-static type_t *type_size_t = NULL;
-static type_t *type_ptrdiff_t = NULL;
+
+type_t *type_size_t = NULL;
+type_t *type_ptrdiff_t = NULL;
+type_t *type_wchar_t = NULL;
+type_t *type_wchar_t_ptr = NULL;
static statement_t *parse_compound_statement(void);
static statement_t *parse_statement(void);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
+static void parse_compound_type_entries(void);
+static declaration_t *parse_declarator(
+ const declaration_specifiers_t *specifiers, bool may_be_abstract);
+static declaration_t *record_declaration(declaration_t *declaration);
+
#define STORAGE_CLASSES \
case T_typedef: \
case T_extern: \
return res;
}
+static size_t get_statement_struct_size(statement_type_t type)
+{
+ static const size_t sizes[] = {
+ [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
+ [STATEMENT_RETURN] = sizeof(return_statement_t),
+ [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
+ [STATEMENT_IF] = sizeof(if_statement_t),
+ [STATEMENT_SWITCH] = sizeof(switch_statement_t),
+ [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
+ [STATEMENT_CONTINUE] = sizeof(statement_base_t),
+ [STATEMENT_BREAK] = sizeof(statement_base_t),
+ [STATEMENT_GOTO] = sizeof(goto_statement_t),
+ [STATEMENT_LABEL] = sizeof(label_statement_t),
+ [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
+ [STATEMENT_WHILE] = sizeof(while_statement_t),
+ [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
+ [STATEMENT_FOR] = sizeof(for_statement_t),
+ [STATEMENT_ASM] = sizeof(asm_statement_t)
+ };
+ assert(sizeof(sizes) / sizeof(sizes[0]) == STATEMENT_ASM + 1);
+ assert(type <= STATEMENT_ASM);
+ assert(sizes[type] != 0);
+ return sizes[type];
+}
+
+static statement_t *allocate_statement_zero(statement_type_t type)
+{
+ size_t size = get_statement_struct_size(type);
+ statement_t *res = allocate_ast_zero(size);
+
+ res->base.type = type;
+ return res;
+}
+
+
static size_t get_expression_struct_size(expression_type_t type)
{
static const size_t sizes[] = {
- [EXPR_INVALID] = sizeof(expression_base_t),
- [EXPR_REFERENCE] = sizeof(reference_expression_t),
- [EXPR_CONST] = sizeof(const_expression_t),
- [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
- [EXPR_CALL] = sizeof(call_expression_t),
- [EXPR_UNARY] = sizeof(unary_expression_t),
- [EXPR_BINARY] = sizeof(binary_expression_t),
- [EXPR_CONDITIONAL] = sizeof(conditional_expression_t),
- [EXPR_SELECT] = sizeof(select_expression_t),
- [EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t),
- [EXPR_SIZEOF] = sizeof(sizeof_expression_t),
- [EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t),
- [EXPR_FUNCTION] = sizeof(string_literal_expression_t),
- [EXPR_PRETTY_FUNCTION] = sizeof(string_literal_expression_t),
- [EXPR_BUILTIN_SYMBOL] = sizeof(builtin_symbol_expression_t),
- [EXPR_OFFSETOF] = sizeof(offsetof_expression_t),
- [EXPR_VA_ARG] = sizeof(va_arg_expression_t),
- [EXPR_STATEMENT] = sizeof(statement_expression_t)
+ [EXPR_INVALID] = sizeof(expression_base_t),
+ [EXPR_REFERENCE] = sizeof(reference_expression_t),
+ [EXPR_CONST] = sizeof(const_expression_t),
+ [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
+ [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t),
+ [EXPR_CALL] = sizeof(call_expression_t),
+ [EXPR_UNARY] = sizeof(unary_expression_t),
+ [EXPR_BINARY] = sizeof(binary_expression_t),
+ [EXPR_CONDITIONAL] = sizeof(conditional_expression_t),
+ [EXPR_SELECT] = sizeof(select_expression_t),
+ [EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t),
+ [EXPR_SIZEOF] = sizeof(sizeof_expression_t),
+ [EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t),
+ [EXPR_FUNCTION] = sizeof(string_literal_expression_t),
+ [EXPR_PRETTY_FUNCTION] = sizeof(string_literal_expression_t),
+ [EXPR_BUILTIN_SYMBOL] = sizeof(builtin_symbol_expression_t),
+ [EXPR_OFFSETOF] = sizeof(offsetof_expression_t),
+ [EXPR_VA_ARG] = sizeof(va_arg_expression_t),
+ [EXPR_STATEMENT] = sizeof(statement_expression_t)
};
assert(sizeof(sizes) / sizeof(sizes[0]) == EXPR_STATEMENT + 1);
assert(type <= EXPR_STATEMENT);
{
assert(num > 0 && num <= MAX_LOOKAHEAD);
int pos = (lookahead_bufpos+num-1) % MAX_LOOKAHEAD;
- return & lookahead_buffer[pos];
+ return &lookahead_buffer[pos];
}
#define eat(token_type) do { assert(token.type == token_type); next_token(); } while(0)
fputs("warning: ", stderr);
}
+static void parser_print_warning_prefix(void)
+{
+ parser_print_warning_prefix_pos(token.source_position);
+}
+
static void parse_warning_pos(const source_position_t source_position,
const char *const message)
{
* called when we find a 2nd declarator for an identifier we already have a
* declarator for
*/
-static bool is_compatible_declaration (declaration_t *declaration,
+static bool is_compatible_declaration(declaration_t *declaration,
declaration_t *previous)
{
+ /* happens for K&R style function parameters */
+ if(previous->type == NULL) {
+ previous->type = declaration->type;
+ return true;
+ }
+
if (declaration->type->type == TYPE_FUNCTION &&
previous->type->type == TYPE_FUNCTION &&
previous->type->function.unspecified_parameters) {
namespace_t namespc = (namespace_t)declaration->namespc;
/* a declaration should be only pushed once */
- assert(declaration->parent_context == NULL);
declaration->parent_context = parent_context;
declaration_t *previous_declaration = get_declaration(symbol, namespc);
return;
for(i = top; i > new_top; --i) {
- stack_entry_t *entry = & stack[i - 1];
+ stack_entry_t *entry = &stack[i - 1];
declaration_t *old_declaration = entry->old_declaration;
symbol_t *symbol = entry->symbol;
{
expression_t *cast = allocate_expression_zero(EXPR_UNARY);
- cast->unary.type = UNEXPR_CAST;
+ cast->unary.type = UNEXPR_CAST_IMPLICIT;
cast->unary.value = expression;
cast->base.datatype = dest_type;
return cast;
}
-static bool is_null_expression(const expression_t *const expression)
+static bool is_null_pointer_constant(const expression_t *expression)
{
+ /* skip void* cast */
+ if(expression->type == EXPR_UNARY) {
+ const unary_expression_t *unary = &expression->unary;
+ if(unary->type == UNEXPR_CAST
+ && expression->base.datatype == type_void_ptr) {
+ expression = unary->value;
+ }
+ }
+
+ /* TODO: not correct yet, should be any constant integer expression
+ * which evaluates to 0 */
if (expression->type != EXPR_CONST)
return false;
case TYPE_POINTER:
switch (source_type->type) {
case TYPE_ATOMIC:
- if (is_null_expression(expression)) {
+ if (is_null_pointer_constant(expression)) {
return create_cast_expression(expression, dest_type);
}
break;
type_t *const type_right = skip_typeref(orig_type_right);
if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
- (is_type_pointer(type_left) && is_null_expression(*right)) ||
+ (is_type_pointer(type_left) && is_null_pointer_constant(*right)) ||
(is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
&& is_type_pointer(type_right))) {
*right = create_implicit_cast(*right, type_left);
parser_print_error_prefix();
fprintf(stderr, "incompatible types in %s\n", context);
parser_print_error_prefix();
- print_type_quoted(type_left);
+ print_type_quoted(orig_type_left);
fputs(" <- ", stderr);
- print_type_quoted(type_right);
+ print_type_quoted(orig_type_right);
fputs("\n", stderr);
}
return parse_sub_expression(2);
}
-typedef struct declaration_specifiers_t declaration_specifiers_t;
-struct declaration_specifiers_t {
- unsigned char storage_class;
- bool is_inline;
- type_t *type;
-};
+static type_t *make_global_typedef(const char *name, type_t *type)
+{
+ symbol_t *symbol = symbol_table_insert(name);
-static void parse_compound_type_entries(void);
-static declaration_t *parse_declarator(
- const declaration_specifiers_t *specifiers, type_t *type,
- bool may_be_abstract);
-static declaration_t *record_declaration(declaration_t *declaration);
+ declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
+ declaration->namespc = NAMESPACE_NORMAL;
+ declaration->storage_class = STORAGE_CLASS_TYPEDEF;
+ declaration->type = type;
+ declaration->symbol = symbol;
+ declaration->source_position = builtin_source_position;
+
+ record_declaration(declaration);
+
+ type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF);
+ typedef_type->typedeft.declaration = declaration;
+
+ return typedef_type;
+}
static const char *parse_string_literals(void)
{
assert(type->type == TYPE_COMPOUND_STRUCT
|| type->type == TYPE_COMPOUND_UNION);
compound_type_t *compound_type = &type->compound;
- context_t *context = & compound_type->declaration->context;
+ context_t *context = &compound_type->declaration->context;
declaration_t *first = context->declarations;
if(first == NULL)
int top = environment_top();
context_t *last_context = context;
- set_context(& declaration->context);
+ set_context(&declaration->context);
parse_compound_type_entries();
parse_attributes();
- assert(context == & declaration->context);
+ assert(context == &declaration->context);
set_context(last_context);
environment_pop_to(top);
}
unsigned type_specifiers = 0;
int newtype = 0;
+ specifiers->source_position = token.source_position;
+
while(true) {
switch(token.type) {
/* invalid specifier combination, give an error message */
if(type_specifiers == 0) {
#ifndef STRICT_C99
- parse_warning("no type specifiers in declaration (using int)");
+ parse_warning("no type specifiers in declaration, using int");
atomic_type = ATOMIC_TYPE_INT;
break;
#else
}
}
-static void parse_identifier_list(void)
+static declaration_t *parse_identifier_list(void)
{
- while(true) {
- if(token.type != T_IDENTIFIER) {
- parse_error_expected("while parsing parameter identifier list",
- T_IDENTIFIER, 0);
- return;
- }
+ declaration_t *declarations = NULL;
+ declaration_t *last_declaration = NULL;
+ do {
declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
- declaration->symbol = token.v.symbol;
+ 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 declaration_t *parse_parameter(void)
parse_declaration_specifiers(&specifiers);
- declaration_t *declaration
- = parse_declarator(&specifiers, specifiers.type, true);
+ declaration_t *declaration = parse_declarator(&specifiers, true);
/* TODO check declaration constraints for parameters */
if(declaration->storage_class == STORAGE_CLASS_TYPEDEF) {
static declaration_t *parse_parameters(function_type_t *type)
{
if(token.type == T_IDENTIFIER) {
- symbol_t *symbol = token.v.symbol;
+ symbol_t *symbol = token.v.symbol;
if(!is_typedef_symbol(symbol)) {
- /* TODO: K&R style C parameters */
- parse_identifier_list();
- return NULL;
+ type->kr_style_parameters = true;
+ return parse_identifier_list();
}
}
}
static declaration_t *parse_declarator(
- const declaration_specifiers_t *specifiers,
- type_t *type, bool may_be_abstract)
+ 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->is_inline = specifiers->is_inline;
static declaration_t *record_declaration(declaration_t *declaration)
{
+ assert(declaration->parent_context == NULL);
assert(context != NULL);
symbol_t *symbol = declaration->symbol;
return declaration;
}
-static void parser_error_multiple_definition(declaration_t *previous,
- declaration_t *declaration)
+static void parser_error_multiple_definition(declaration_t *declaration,
+ const source_position_t source_position)
{
- parser_print_error_prefix_pos(declaration->source_position);
+ parser_print_error_prefix_pos(source_position);
fprintf(stderr, "multiple definition of symbol '%s'\n",
declaration->symbol->string);
- parser_print_error_prefix_pos(previous->source_position);
+ parser_print_error_prefix_pos(declaration->source_position);
fprintf(stderr, "this is the location of the previous definition.\n");
}
-static void parse_init_declarators(const declaration_specifiers_t *specifiers)
+static bool is_declaration_specifier(const token_t *token,
+ bool only_type_specifiers)
{
- while(true) {
- declaration_t *ndeclaration
- = parse_declarator(specifiers, specifiers->type, false);
+ 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 intializers for arrays with unknown size determine
+ * the array type size */
+ if(type != NULL && type->type == TYPE_ARRAY && 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;
+
+ if(initializer->type == INITIALIZER_LIST) {
+ initializer_list_t *list = &initializer->list;
+ cnst->conste.v.int_value = list->len;
+ } else {
+ assert(initializer->type == INITIALIZER_STRING);
+ initializer_string_t *string = &initializer->string;
+ cnst->conste.v.int_value = strlen(string->string) + 1;
+ }
- declaration_t *declaration = record_declaration(ndeclaration);
+ array_type->size = cnst;
+ }
+ }
+
+ if(type != NULL && type->type == TYPE_FUNCTION) {
+ parser_print_error_prefix_pos(declaration->source_position);
+ fprintf(stderr, "initializers not allowed for function types at "
+ "declator '%s' (type ", declaration->symbol->string);
+ print_type_quoted(orig_type);
+ fprintf(stderr, ")\n");
+ } 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) {
+ parse_warning_pos(declaration->source_position,
+ "useless storage class in empty declaration");
+ }
+
+ type_t *type = declaration->type;
+ switch (type->type) {
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: {
+ const compound_type_t *compound_type = &type->compound;
+ if (compound_type->declaration->symbol == NULL) {
+ parse_warning_pos(declaration->source_position,
+ "unnamed struct/union that defines no instances");
+ }
+ break;
+ }
+
+ case TYPE_ENUM:
+ break;
+
+ default:
+ parse_warning_pos(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->type != TYPE_FUNCTION && declaration->is_inline) {
parser_print_warning_prefix_pos(declaration->source_position);
fprintf(stderr, "variable '%s' declared 'inline'\n",
- declaration->symbol->string);
+ declaration->symbol->string);
}
if(token.type == '=') {
- next_token();
+ parse_init_declarator_rest(declaration);
+ }
- /* TODO: check that this is an allowed type (no function type) */
+ if(token.type != ',')
+ break;
+ eat(',');
- if(declaration->init.initializer != NULL) {
- parser_error_multiple_definition(declaration, ndeclaration);
- }
+ ndeclaration = parse_declarator(specifiers, false);
+ }
+ expect_void(';');
+}
+
+static declaration_t *finished_kr_declaration(declaration_t *declaration)
+{
+ /* TODO: check that it was actually a parameter that gets a type */
+
+ /* we should have a declaration for the parameter in the current
+ * scope */
+ return record_declaration(declaration);
+}
- initializer_t *initializer = parse_initializer(type);
+static void parse_declaration(parsed_declaration_func finished_declaration)
+{
+ declaration_specifiers_t specifiers;
+ memset(&specifiers, 0, sizeof(specifiers));
+ parse_declaration_specifiers(&specifiers);
- if(type->type == TYPE_ARRAY && initializer != NULL) {
- array_type_t *array_type = &type->array;
+ if(token.type == ';') {
+ parse_anonymous_declaration_rest(&specifiers, finished_declaration);
+ } else {
+ declaration_t *declaration = parse_declarator(&specifiers, false);
+ parse_declaration_rest(declaration, &specifiers, finished_declaration);
+ }
+}
- if(array_type->size == NULL) {
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+static void parse_kr_declaration_list(declaration_t *declaration)
+{
+ type_t *type = skip_typeref(declaration->type);
+ assert(type->type == TYPE_FUNCTION);
- cnst->base.datatype = type_size_t;
+ if(!type->function.kr_style_parameters)
+ return;
- if(initializer->type == INITIALIZER_LIST) {
- initializer_list_t *list = &initializer->list;
- cnst->conste.v.int_value = list->len;
- } else {
- assert(initializer->type == INITIALIZER_STRING);
- initializer_string_t *string = &initializer->string;
- cnst->conste.v.int_value = strlen(string->string) + 1;
- }
+ /* push function parameters */
+ int top = environment_top();
+ context_t *last_context = context;
+ set_context(&declaration->context);
- array_type->size = cnst;
- }
- }
+ declaration_t *parameter = declaration->context.declarations;
+ for( ; parameter != NULL; parameter = parameter->next) {
+ environment_push(parameter);
+ }
+ /* parse declaration list */
+ while(is_declaration_specifier(&token, false)) {
+ parse_declaration(finished_kr_declaration);
+ }
- 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;
- }
- function_type_t *function_type = &type->function;
- /* § 6.7.5.3 (14) a function definition with () */
- if(function_type->unspecified_parameters) {
- type_t *duplicate = duplicate_type(type);
- duplicate->function.unspecified_parameters = true;
-
- type = typehash_insert(duplicate);
- if(type != duplicate) {
- obstack_free(type_obst, duplicate);
- }
- function_type = &type->function;
- }
+ /* pop function parameters */
+ assert(context == &declaration->context);
+ set_context(last_context);
+ environment_pop_to(top);
- if(declaration->init.statement != NULL) {
- parser_error_multiple_definition(declaration, ndeclaration);
- }
- if(ndeclaration != declaration) {
- memcpy(&declaration->context, &ndeclaration->context,
- sizeof(declaration->context));
- }
+ /* update function type */
+ type_t *new_type = duplicate_type(type);
+ new_type->function.kr_style_parameters = false;
- int top = environment_top();
- context_t *last_context = context;
- set_context(&declaration->context);
+ function_parameter_t *parameters = NULL;
+ function_parameter_t *last_parameter = NULL;
- /* push function parameters */
- declaration_t *parameter = declaration->context.declarations;
- for( ; parameter != NULL; parameter = parameter->next) {
- environment_push(parameter);
- }
+ 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) {
+#ifdef STRICT_C99
+ parser_print_error_prefix();
+ fprintf(stderr, "no type specified for function parameter '%s'\n",
+ parameter_declaration->symbol->string);
+#else
+ parser_print_warning_prefix();
+ fprintf(stderr, "no type specified for function parameter '%s', "
+ "using int\n", parameter_declaration->symbol->string);
+ parameter_type = type_int;
+ parameter_declaration->type = parameter_type;
+#endif
+ }
- int label_stack_top = label_top();
- declaration_t *old_current_function = current_function;
- current_function = declaration;
+ function_parameter_t *function_parameter
+ = obstack_alloc(type_obst, sizeof(function_parameter[0]));
+ memset(function_parameter, 0, sizeof(function_parameter[0]));
- statement_t *statement = parse_compound_statement();
+ 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;
- assert(current_function == declaration);
- current_function = old_current_function;
- label_pop_to(label_stack_top);
+ type = typehash_insert(new_type);
+ if(type != new_type) {
+ obstack_free(type_obst, new_type);
+ }
- assert(context == &declaration->context);
- set_context(last_context);
- environment_pop_to(top);
+ declaration->type = type;
+}
- declaration->init.statement = statement;
- return;
+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, record_declaration);
+ return;
+ }
+
+ /* declarator is common to both function-definitions and declarations */
+ declaration_t *ndeclaration = parse_declarator(&specifiers, 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);
+
+ declaration_t *declaration = record_declaration(ndeclaration);
+ if(ndeclaration != declaration) {
+ memcpy(&declaration->context, &ndeclaration->context,
+ sizeof(declaration->context));
+ }
+
+ /* 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) {
+ environment_push(parameter);
+ }
+
+ type_t *orig_type;
+ type_t *type;
+
+ if(token.type != '{') {
+ parse_error_expected("while parsing function definition", '{', 0);
+ eat_statement();
+ goto end_of_parse_external_declaration;
+ }
+
+ orig_type = declaration->type;
+ if(orig_type == NULL) {
+ eat_block();
+ goto end_of_parse_external_declaration;
+ }
+
+ type = skip_typeref(orig_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();
+ goto end_of_parse_external_declaration;
+ }
+
+ /* § 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);
}
+ declaration->type = type;
+ }
- if(token.type != ',')
- break;
- next_token();
+ if(declaration->init.statement != NULL) {
+ parser_error_multiple_definition(declaration, token.source_position);
+ eat_block();
+ goto end_of_parse_external_declaration;
}
- expect_void(';');
+
+ /* 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 void parse_struct_declarators(const declaration_specifiers_t *specifiers)
parse_constant_expression();
/* TODO (bitfields) */
} else {
- declaration_t *declaration
- = parse_declarator(specifiers, specifiers->type, true);
+ declaration_t *declaration = parse_declarator(specifiers, true);
/* TODO: check constraints for struct declarations */
/* TODO: check for doubled fields */
parse_struct_declarators(&specifiers);
}
if(token.type == T_EOF) {
- parse_error("unexpected error while parsing struct");
+ parse_error("EOF 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
- = &specifiers.type->compound;
- 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;
{
parser_print_error_prefix();
fprintf(stderr, "expected expression, got token ");
- print_token(stderr, & token);
+ print_token(stderr, &token);
fprintf(stderr, "\n");
next_token();
return cnst;
}
+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;
+}
+
static expression_t *parse_int_const(void)
{
expression_t *cnst = allocate_expression_zero(EXPR_CONST);
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);
default:
panic("not implemented builtin symbol found");
}
return parse_int_const();
case T_FLOATINGPOINT:
return parse_float_const();
- case T_STRING_LITERAL:
+ case T_STRING_LITERAL: /* TODO merge */
return parse_string_const();
+ case T_WIDE_STRING_LITERAL:
+ return parse_wide_string_const();
case T_IDENTIFIER:
return parse_reference();
case T___FUNCTION__:
return parse_offsetof();
case T___builtin_va_arg:
return parse_va_arg();
+ case T___builtin_nanf:
case T___builtin_alloca:
case T___builtin_expect:
case T___builtin_va_start:
return (expression_t*) array_access;
}
-static bool is_declaration_specifier(const token_t *token,
- bool only_type_specifiers)
-{
- switch(token->type) {
- TYPE_SPECIFIERS
- return 1;
- case T_IDENTIFIER:
- return is_typedef_symbol(token->v.symbol);
- STORAGE_CLASSES
- TYPE_QUALIFIERS
- if(only_type_specifiers)
- return 0;
- return 1;
-
- default:
- return 0;
- }
-}
-
static expression_t *parse_sizeof(unsigned precedence)
{
eat(T_sizeof);
/* do default promotion */
for( ; argument != NULL; argument = argument->next) {
type_t *type = argument->expression->base.datatype;
- type = skip_typeref(type);
if(type == NULL)
continue;
+ type = skip_typeref(type);
if(is_type_integer(type)) {
type = promote_integer(type);
} else if(type == type_float) {
static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right);
+static bool same_compound_type(const type_t *type1, const type_t *type2)
+{
+ if(!is_type_compound(type1))
+ return false;
+ if(type1->type != type2->type)
+ return false;
+
+ const compound_type_t *compound1 = &type1->compound;
+ const compound_type_t *compound2 = &type2->compound;
+
+ return compound1->declaration == compound2->declaration;
+}
+
static expression_t *parse_conditional_expression(unsigned precedence,
expression_t *expression)
{
eat('?');
- conditional_expression_t *conditional
- = allocate_ast_zero(sizeof(conditional[0]));
- conditional->expression.type = EXPR_CONDITIONAL;
- conditional->condition = expression;
+ expression_t *result = allocate_expression_zero(EXPR_CONDITIONAL);
+
+ conditional_expression_t *conditional = &result->conditional;
+ conditional->condition = expression;
/* 6.5.15.2 */
- type_t *condition_type_orig = conditional->condition->base.datatype;
+ type_t *condition_type_orig = expression->base.datatype;
if(condition_type_orig != NULL) {
- type_t *condition_type = skip_typeref(condition_type_orig);
+ type_t *condition_type = skip_typeref(condition_type_orig);
if(condition_type != NULL && !is_type_scalar(condition_type)) {
- type_error("expected a scalar type",
+ type_error("expected a scalar type in conditional condition",
expression->base.source_position, condition_type_orig);
}
}
- expression_t *const t_expr = parse_expression();
- conditional->true_expression = t_expr;
+ expression_t *true_expression = parse_expression();
expect(':');
- expression_t *const f_expr = parse_sub_expression(precedence);
- conditional->false_expression = f_expr;
+ expression_t *false_expression = parse_sub_expression(precedence);
- type_t *const true_type = t_expr->base.datatype;
- if(true_type == NULL)
- return (expression_t*) conditional;
- type_t *const false_type = f_expr->base.datatype;
- if(false_type == NULL)
- return (expression_t*) conditional;
+ conditional->true_expression = true_expression;
+ conditional->false_expression = false_expression;
+
+ type_t *orig_true_type = true_expression->base.datatype;
+ type_t *orig_false_type = false_expression->base.datatype;
+ if(orig_true_type == NULL || orig_false_type == NULL)
+ return result;
- type_t *const skipped_true_type = skip_typeref(true_type);
- type_t *const skipped_false_type = skip_typeref(false_type);
+ type_t *true_type = skip_typeref(orig_true_type);
+ type_t *false_type = skip_typeref(orig_false_type);
/* 6.5.15.3 */
- if (skipped_true_type == skipped_false_type) {
- conditional->expression.datatype = skipped_true_type;
- } else if (is_type_arithmetic(skipped_true_type) &&
- is_type_arithmetic(skipped_false_type)) {
- type_t *const result = semantic_arithmetic(skipped_true_type,
- skipped_false_type);
- conditional->true_expression = create_implicit_cast(t_expr, result);
- conditional->false_expression = create_implicit_cast(f_expr, result);
- conditional->expression.datatype = result;
- } else if (skipped_true_type->type == TYPE_POINTER &&
- skipped_false_type->type == TYPE_POINTER &&
- true /* TODO compatible points_to types */) {
- /* TODO */
- } else if(/* (is_null_ptr_const(skipped_true_type) &&
- skipped_false_type->type == TYPE_POINTER)
- || (is_null_ptr_const(skipped_false_type) &&
- skipped_true_type->type == TYPE_POINTER) TODO*/ false) {
- /* TODO */
- } else if(/* 1 is pointer to object type, other is void* */ false) {
- /* TODO */
+ type_t *result_type = NULL;
+ if (is_type_arithmetic(true_type) && is_type_arithmetic(false_type)) {
+ result_type = semantic_arithmetic(true_type, false_type);
+
+ true_expression = create_implicit_cast(true_expression, result_type);
+ false_expression = create_implicit_cast(false_expression, result_type);
+
+ conditional->true_expression = true_expression;
+ conditional->false_expression = false_expression;
+ conditional->expression.datatype = result_type;
+ } else if (same_compound_type(true_type, false_type)
+ || (is_type_atomic(true_type, ATOMIC_TYPE_VOID) &&
+ is_type_atomic(false_type, ATOMIC_TYPE_VOID))) {
+ /* just take 1 of the 2 types */
+ result_type = true_type;
+ } else if (is_type_pointer(true_type) && is_type_pointer(false_type)
+ && pointers_compatible(true_type, false_type)) {
+ /* ok */
+ result_type = true_type;
} else {
+ /* TODO */
type_error_incompatible("while parsing conditional",
expression->base.source_position, true_type,
- skipped_false_type);
+ false_type);
}
- return (expression_t*) conditional;
+ conditional->expression.datatype = result_type;
+ return result;
}
static expression_t *parse_extension(unsigned precedence)
{
eat(T___builtin_classify_type);
- classify_type_expression_t *const classify_type_expr =
- allocate_ast_zero(sizeof(classify_type_expr[0]));
- classify_type_expr->expression.type = EXPR_CLASSIFY_TYPE;
- classify_type_expr->expression.datatype = type_int;
+ expression_t *result = allocate_expression_zero(EXPR_CLASSIFY_TYPE);
+ result->base.datatype = type_int;
expect('(');
- expression_t *const expression = parse_sub_expression(precedence);
+ expression_t *expression = parse_sub_expression(precedence);
expect(')');
- classify_type_expr->type_expression = expression;
+ result->classify_type.type_expression = expression;
- return (expression_t*)classify_type_expr;
+ return result;
}
static void semantic_incdec(unary_expression_t *expression)
T___builtin_classify_type, 25);
}
+static asm_constraint_t *parse_asm_constraints(void)
+{
+ asm_constraint_t *result = NULL;
+ asm_constraint_t *last = NULL;
+
+ while(token.type == T_STRING_LITERAL || token.type == '[') {
+ asm_constraint_t *constraint = allocate_ast_zero(sizeof(constraint[0]));
+ memset(constraint, 0, sizeof(constraint[0]));
+
+ if(token.type == '[') {
+ eat('[');
+ if(token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing asm constraint",
+ T_IDENTIFIER, 0);
+ return NULL;
+ }
+ constraint->symbol = token.v.symbol;
+
+ expect(']');
+ }
+
+ constraint->constraints = parse_string_literals();
+ expect('(');
+ constraint->expression = parse_expression();
+ expect(')');
+
+ if(last != NULL) {
+ last->next = constraint;
+ } else {
+ result = constraint;
+ }
+ last = constraint;
+
+ if(token.type != ',')
+ break;
+ eat(',');
+ }
+
+ return result;
+}
+
+static asm_clobber_t *parse_asm_clobbers(void)
+{
+ asm_clobber_t *result = NULL;
+ asm_clobber_t *last = NULL;
+
+ while(token.type == T_STRING_LITERAL) {
+ asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0]));
+ clobber->clobber = parse_string_literals();
+
+ if(last != NULL) {
+ last->next = clobber;
+ } else {
+ result = clobber;
+ }
+ last = clobber;
+
+ if(token.type != ',')
+ break;
+ eat(',');
+ }
+
+ return result;
+}
+
+static statement_t *parse_asm_statement(void)
+{
+ eat(T_asm);
+
+ statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
+ statement->base.source_position = token.source_position;
+
+ asm_statement_t *asm_statement = &statement->asms;
+
+ if(token.type == T_volatile) {
+ next_token();
+ asm_statement->is_volatile = true;
+ }
+
+ expect('(');
+ asm_statement->asm_text = parse_string_literals();
+
+ if(token.type != ':')
+ goto end_of_asm;
+ eat(':');
+
+ asm_statement->inputs = parse_asm_constraints();
+ if(token.type != ':')
+ goto end_of_asm;
+ eat(':');
+
+ asm_statement->outputs = parse_asm_constraints();
+ if(token.type != ':')
+ goto end_of_asm;
+ eat(':');
+
+ asm_statement->clobbers = parse_asm_clobbers();
+
+end_of_asm:
+ expect(')');
+ expect(';');
+ return statement;
+}
static statement_t *parse_case_statement(void)
{
eat(T_case);
- case_label_statement_t *label = allocate_ast_zero(sizeof(label[0]));
- label->statement.type = STATEMENT_CASE_LABEL;
- label->statement.source_position = token.source_position;
- label->expression = parse_expression();
+ statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
+
+ statement->base.source_position = token.source_position;
+ statement->case_label.expression = parse_expression();
expect(':');
- label->label_statement = parse_statement();
+ statement->case_label.label_statement = parse_statement();
- return (statement_t*) label;
+ return statement;
}
static statement_t *parse_default_statement(void)
{
eat(T_default);
- case_label_statement_t *label = allocate_ast_zero(sizeof(label[0]));
- label->statement.type = STATEMENT_CASE_LABEL;
- label->statement.source_position = token.source_position;
+ statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
+
+ statement->base.source_position = token.source_position;
expect(':');
- label->label_statement = parse_statement();
+ statement->label.label_statement = parse_statement();
- return (statement_t*) label;
+ return statement;
}
static declaration_t *get_label(symbol_t *symbol)
/* otherwise we need to create a new one */
declaration_t *declaration = allocate_ast_zero(sizeof(declaration[0]));
- declaration->namespc = NAMESPACE_LABEL;
+ declaration->namespc = NAMESPACE_LABEL;
declaration->symbol = symbol;
label_push(declaration);
if(token.type != ';') {
if(is_declaration_specifier(&token, false)) {
- parse_declaration();
+ parse_declaration(record_declaration);
} else {
statement->initialisation = parse_expression();
expect(';');
static statement_t *parse_declaration_statement(void)
{
- declaration_t *before = last_declaration;
-
- declaration_statement_t *statement
- = allocate_ast_zero(sizeof(statement[0]));
- statement->statement.type = STATEMENT_DECLARATION;
- statement->statement.source_position = token.source_position;
+ statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
- declaration_specifiers_t specifiers;
- memset(&specifiers, 0, sizeof(specifiers));
- parse_declaration_specifiers(&specifiers);
+ statement->base.source_position = token.source_position;
- if(token.type == ';') {
- eat(';');
- } else {
- parse_init_declarators(&specifiers);
- }
+ declaration_t *before = last_declaration;
+ parse_declaration(record_declaration);
if(before == NULL) {
- statement->declarations_begin = context->declarations;
+ statement->declaration.declarations_begin = context->declarations;
} else {
- statement->declarations_begin = before->next;
+ statement->declaration.declarations_begin = before->next;
}
- statement->declarations_end = last_declaration;
+ statement->declaration.declarations_end = last_declaration;
- return (statement_t*) statement;
+ return statement;
}
static statement_t *parse_expression_statement(void)
{
- expression_statement_t *statement = allocate_ast_zero(sizeof(statement[0]));
- statement->statement.type = STATEMENT_EXPRESSION;
- statement->statement.source_position = token.source_position;
+ statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION);
- statement->expression = parse_expression();
+ statement->base.source_position = token.source_position;
+ statement->expression.expression = parse_expression();
expect(';');
- return (statement_t*) statement;
+ return statement;
}
static statement_t *parse_statement(void)
/* declaration or statement */
switch(token.type) {
+ case T_asm:
+ statement = parse_asm_statement();
+ break;
+
case T_case:
statement = parse_case_statement();
break;
return (statement_t*) compound_statement;
}
+static void initialize_builtins(void)
+{
+ type_wchar_t = make_global_typedef("__WCHAR_TYPE__", type_int);
+ type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE);
+ type_size_t = make_global_typedef("__SIZE_TYPE__",
+ make_atomic_type(ATOMIC_TYPE_ULONG, TYPE_QUALIFIER_NONE));
+ type_ptrdiff_t = make_global_typedef("__PTRDIFF_TYPE__",
+ make_atomic_type(ATOMIC_TYPE_LONG, TYPE_QUALIFIER_NONE));
+}
+
static translation_unit_t *parse_translation_unit(void)
{
translation_unit_t *unit = allocate_ast_zero(sizeof(unit[0]));
assert(context == NULL);
set_context(&unit->context);
+ initialize_builtins();
+
while(token.type != T_EOF) {
- parse_declaration();
+ parse_external_declaration();
}
assert(context == &unit->context);
obstack_init(&temp_obst);
type_int = make_atomic_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
- type_long_double = make_atomic_type(ATOMIC_TYPE_LONG_DOUBLE, TYPE_QUALIFIER_NONE);
- type_double = make_atomic_type(ATOMIC_TYPE_DOUBLE, TYPE_QUALIFIER_NONE);
+ type_long_double = make_atomic_type(ATOMIC_TYPE_LONG_DOUBLE,
+ TYPE_QUALIFIER_NONE);
+ type_double = make_atomic_type(ATOMIC_TYPE_DOUBLE,
+ TYPE_QUALIFIER_NONE);
type_float = make_atomic_type(ATOMIC_TYPE_FLOAT, TYPE_QUALIFIER_NONE);
- type_size_t = make_atomic_type(ATOMIC_TYPE_ULONG, TYPE_QUALIFIER_NONE);
- type_ptrdiff_t = make_atomic_type(ATOMIC_TYPE_LONG, TYPE_QUALIFIER_NONE);
type_char = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_NONE);
type_void = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
type_void_ptr = make_pointer_type(type_void, TYPE_QUALIFIER_NONE);