+Initializer rewrite:
+- determining of array size for array types of unspecified length is wrong in
+ presence of designators and unions
+
Refactoring:
- create an empty_statement_t and use that instead of a NULL pointer in places
like if, loop bodys, statements after labels
+- eliminate target_architecture.h and replace with stuff in lang_features.h
Lexer:
- Add preprocessor code
Parser:
- the expect macros abort functions directly. This leads to some functions
- not resetting the current context properly (parse_for)
+ not resetting the current context properly (parse_for); expect in expressions
+ suddenly return NULL which triggers asserts
- label: declaration; is no valid C99 but we parse it anyway
- designator support for initializers
- add constant folding code
-- Refactor code, so code to handle number values and strings is
- an own module and replacable
+- Refactor code, so code to handle number values (and strings?) is an own
+ module and replacable
- Support some attributes. noreturn, unused, printf, scanf, packed would be
interesting candidates
+- Add columns to source positions
- SourcePositions could be stored selectively on expressions that really need
them.
- check semantic for functions declared/defined in global scope and declared
again in a local scope
ast2firm:
+- handle non-constant initializers
- output source file positions for panics...
-- output variable names for uninitialized variable warnings
- handle bitfield members with 0 correctly (standard says they finish the
current unit)
[EXPR_CONST] = PREC_PRIM,
[EXPR_STRING_LITERAL] = PREC_PRIM,
[EXPR_WIDE_STRING_LITERAL] = PREC_PRIM,
+ [EXPR_COMPOUND_LITERAL] = PREC_UNARY,
[EXPR_CALL] = PREC_PRIM,
[EXPR_CONDITIONAL] = PREC_COND,
[EXPR_SELECT] = PREC_ACCESS,
*
* @param wstr the wide string literal expression
*/
-static void print_wide_string_literal(
- const wide_string_literal_expression_t *const wstr)
+static void print_quoted_wide_string(const wide_string_t *const wstr)
{
fputs("L\"", out);
- for (const wchar_rep_t *c = wstr->value.begin,
- *end = c + wstr->value.size;
+ for (const wchar_rep_t *c = wstr->begin, *end = wstr->begin + wstr->size;
c != end; ++c) {
switch (*c) {
case L'\"': fputs("\\\"", out); break;
fputc('"', out);
}
+static void print_wide_string_literal(
+ const wide_string_literal_expression_t *const wstr)
+{
+ print_quoted_wide_string(&wstr->value);
+}
+
+static void print_compound_literal(
+ const compound_literal_expression_t *expression)
+{
+ fputc('(', out);
+ print_type(expression->type);
+ fputs(") ", out);
+ print_initializer(expression->initializer);
+}
+
/**
* Prints a call expression.
*
*/
static void print_designator(const designator_t *designator)
{
- fputs(designator->symbol->string, out);
- for (designator = designator->next; designator != NULL; designator = designator->next) {
- if (designator->array_access) {
+ for ( ; designator != NULL; designator = designator->next) {
+ if (designator->symbol == NULL) {
fputc('[', out);
- print_expression_prec(designator->array_access, PREC_ACCESS);
+ print_expression_prec(designator->array_index, PREC_ACCESS);
fputc(']', out);
} else {
fputc('.', out);
case EXPR_WIDE_STRING_LITERAL:
print_wide_string_literal(&expression->wide_string);
break;
+ case EXPR_COMPOUND_LITERAL:
+ print_compound_literal(&expression->compound_literal);
+ break;
case EXPR_CALL:
print_call_expression(&expression->call);
break;
*/
void print_initializer(const initializer_t *initializer)
{
- if(initializer->kind == INITIALIZER_VALUE) {
+ if(initializer == NULL) {
+ fputs("{ NIL-INITIALIZER }", out);
+ return;
+ }
+
+ switch(initializer->kind) {
+ case INITIALIZER_VALUE: {
const initializer_value_t *value = &initializer->value;
print_expression(value->value);
return;
}
-
- assert(initializer->kind == INITIALIZER_LIST);
- fputs("{ ", out);
- const initializer_list_t *list = &initializer->list;
-
- for(size_t i = 0 ; i < list->len; ++i) {
- if(i > 0) {
- fputs(", ", out);
+ case INITIALIZER_LIST: {
+ assert(initializer->kind == INITIALIZER_LIST);
+ fputs("{ ", out);
+ const initializer_list_t *list = &initializer->list;
+
+ for(size_t i = 0 ; i < list->len; ++i) {
+ const initializer_t *sub_init = list->initializers[i];
+ print_initializer(list->initializers[i]);
+ if(i < list->len-1 && sub_init->kind != INITIALIZER_DESIGNATOR) {
+ fputs(", ", out);
+ }
}
- print_initializer(list->initializers[i]);
+ fputs(" }", out);
+ return;
}
- fputs("}", out);
+ case INITIALIZER_STRING:
+ print_quoted_string(&initializer->string.string, '"');
+ return;
+ case INITIALIZER_WIDE_STRING:
+ print_quoted_wide_string(&initializer->wide_string.string);
+ return;
+ case INITIALIZER_DESIGNATOR:
+ print_designator(initializer->designator.designator);
+ fputs(" = ", out);
+ return;
+ }
+
+ panic("invalid initializer kind found");
}
/**
return is_constant_expression(expression->binary.left)
&& is_constant_expression(expression->binary.right);
+ case EXPR_COMPOUND_LITERAL:
+ /* TODO: check initializer if it is constant */
+ return true;
+
case EXPR_CONDITIONAL:
/* TODO: not correct, we only have to test expressions which are
* evaluated, which means either the true or false part might be not
typedef struct const_expression_t const_expression_t;
typedef struct string_literal_expression_t string_literal_expression_t;
typedef struct wide_string_literal_expression_t wide_string_literal_expression_t;
+typedef struct compound_literal_expression_t compound_literal_expression_t;
typedef struct reference_expression_t reference_expression_t;
typedef struct cast_expression_t cast_expression_t;
typedef struct call_argument_t call_argument_t;
typedef struct initializer_value_t initializer_value_t;
typedef struct initializer_string_t initializer_string_t;
typedef struct initializer_wide_string_t initializer_wide_string_t;
+typedef struct initializer_designator_t initializer_designator_t;
typedef union initializer_t initializer_t;
typedef struct declaration_t declaration_t;
bool is_constant_expression(const expression_t *expression);
+long fold_constant(const expression_t *expression);
+
#endif
#include "parser.h"
#include "diagnostic.h"
#include "lang_features.h"
+#include "types.h"
#include "driver/firm_opt.h"
#include "driver/firm_cmdline.h"
static ir_type *ir_type_int;
static type_t *type_const_char;
-static type_t *type_void;
-static type_t *type_int;
static int next_value_number_function;
static ir_node *continue_label;
{
const declaration_t *declaration = get_irg_loc_description(irg, pos);
- warningf(declaration->source_position, "variable '%#T' might be used uninitialized",
- declaration->type, declaration->symbol);
+ warningf(declaration->source_position,
+ "variable '%#T' might be used uninitialized",
+ declaration->type, declaration->symbol);
return new_r_Unknown(irg, mode);
}
}
-
-
-static long fold_constant(const expression_t *expression);
-
static ir_type *create_atomic_type(const atomic_type_t *type)
{
dbg_info *dbgi = get_dbg_info(&type->type.source_position);
type_t *element_type = type->element_type;
ir_type *ir_element_type = get_ir_type(element_type);
- ident *id = unique_ident("array");
- dbg_info *dbgi = get_dbg_info(&type->type.source_position);
- ir_type *ir_type = new_d_type_array(id, 1, ir_element_type, dbgi);
+ ident *id = unique_ident("array");
+ dbg_info *dbgi = get_dbg_info(&type->type.source_position);
+ ir_type *ir_type = new_d_type_array(id, 1, ir_element_type, dbgi);
const int align = get_type_alignment_bytes(ir_element_type);
set_type_alignment_bytes(ir_type, align);
- if(type->size != NULL) {
- int n_elements = fold_constant(type->size);
+ if(type->size_constant) {
+ int n_elements = type->size;
set_array_bounds_int(ir_type, 0, 0, n_elements);
return declaration->v.irtype;
}
- size_t offset = 0;
size_t align_all = 1;
+ size_t offset = 0;
size_t size = 0;
if(irtype == NULL) {
dbg_info *dbgi = get_dbg_info(&type->type.source_position);
irtype = new_d_type_union(id, dbgi);
+
+ declaration->v.irtype = irtype;
+ type->type.firm_type = irtype;
} else {
offset = *outer_offset;
align_all = *outer_align;
if(entry->namespc != NAMESPACE_NORMAL)
continue;
- type_t *entry_type = skip_typeref(entry->type);
- ir_type *entry_ir_type = get_ir_type(entry_type);
+ symbol_t *symbol = entry->symbol;
+ type_t *entry_type = skip_typeref(entry->type);
+ ir_type *entry_ir_type = get_ir_type(entry_type);
ident *ident;
- if(entry->symbol != NULL) {
+ if(symbol != NULL) {
ident = new_id_from_str(entry->symbol->string);
} else {
size_t offs = offset;
{
type->type.firm_type = ir_type_int;
- ir_mode *const mode = get_ir_mode((type_t*) type);
+ ir_mode *const mode = mode_int;
tarval *const one = get_mode_one(mode);
tarval * tv_next = get_tarval_null(mode);
const char *const id_prefix,
const string_t *const value)
{
- ir_type *const global_type = get_glob_type();
- dbg_info *const dbgi = get_dbg_info(src_pos);
- ir_type *const type = new_d_type_array(unique_ident("strtype"), 1,
- ir_type_const_char, dbgi);
+ ir_type *const global_type = get_glob_type();
+ dbg_info *const dbgi = get_dbg_info(src_pos);
+ ir_type *const type = new_d_type_array(unique_ident("strtype"), 1,
+ ir_type_const_char, dbgi);
ident *const id = unique_ident(id_prefix);
ir_entity *const entity = new_d_entity(global_type, id, type, dbgi);
return deref_address(irtype, addr, dbgi);
}
+static long get_offsetof_offset(const offsetof_expression_t *expression)
+{
+ type_t *orig_type = expression->type;
+ long offset = 0;
+
+ designator_t *designator = expression->designator;
+ for( ; designator != NULL; designator = designator->next) {
+ type_t *type = skip_typeref(orig_type);
+ /* be sure the type is constructed */
+ (void) get_ir_type(type);
+
+ if(designator->symbol != NULL) {
+ assert(is_type_compound(type));
+ symbol_t *symbol = designator->symbol;
+
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next) {
+ if(iter->symbol == symbol) {
+ break;
+ }
+ }
+ assert(iter != NULL);
+
+ assert(iter->declaration_kind == DECLARATION_KIND_COMPOUND_MEMBER);
+ offset += get_entity_offset(iter->v.entity);
+
+ orig_type = iter->type;
+ } else {
+ expression_t *array_index = designator->array_index;
+ assert(designator->array_index != NULL);
+ assert(is_type_array(type));
+ assert(is_type_valid(array_index->base.type));
+
+ long index = fold_constant(array_index);
+ ir_type *arr_type = get_ir_type(type);
+ ir_type *elem_type = get_array_element_type(arr_type);
+ long elem_size = get_type_size_bytes(elem_type);
+
+ offset += index * elem_size;
+
+ orig_type = type->array.element_type;
+ }
+ }
+
+ return offset;
+}
+
+static ir_node *offsetof_to_firm(const offsetof_expression_t *expression)
+{
+ ir_mode *mode = get_ir_mode(expression->base.type);
+ long offset = get_offsetof_offset(expression);
+ tarval *tv = new_tarval_from_long(offset, mode);
+ dbg_info *dbgi = get_dbg_info(&expression->base.source_position);
+
+ return new_d_Const(dbgi, mode, tv);
+}
+
+static ir_node *compound_literal_to_firm(
+ const compound_literal_expression_t *expression)
+{
+ /* create an entity on the stack */
+ ir_type *frame_type = get_irg_frame_type(current_ir_graph);
+
+ ident *const id = unique_ident("CompLit");
+ ir_type *const irtype = get_ir_type(expression->type);
+ dbg_info *const dbgi = get_dbg_info(&expression->base.source_position);
+ ir_entity *const entity = new_d_entity(frame_type, id, irtype, dbgi);
+ set_entity_ld_ident(entity, id);
+
+ set_entity_variability(entity, variability_uninitialized);
+
+ /* create initialisation code TODO */
+ return NULL;
+}
+
/**
* Transform a sizeof expression into Firm code.
*/
return new_SymConst(mode, sym, symconst_type_align);
}
-static long fold_constant(const expression_t *expression)
+static void init_ir_types(void);
+long fold_constant(const expression_t *expression)
{
+ init_ir_types();
+
assert(is_constant_expression(expression));
ir_graph *old_current_ir_graph = current_ir_graph;
return va_start_expression_to_firm(&expression->va_starte);
case EXPR_VA_ARG:
return va_arg_expression_to_firm(&expression->va_arge);
- case EXPR_OFFSETOF:
case EXPR_BUILTIN_SYMBOL:
panic("unimplemented expression found");
case EXPR_BUILTIN_CONSTANT_P:
return builtin_constant_to_firm(&expression->builtin_constant);
case EXPR_BUILTIN_PREFETCH:
return builtin_prefetch_to_firm(&expression->builtin_prefetch);
+ case EXPR_OFFSETOF:
+ return offsetof_to_firm(&expression->offsetofe);
+ case EXPR_COMPOUND_LITERAL:
+ return compound_literal_to_firm(&expression->compound_literal);
case EXPR_UNKNOWN:
case EXPR_INVALID:
/* TODO: visibility? */
}
+
+typedef struct type_path_entry_t type_path_entry_t;
+struct type_path_entry_t {
+ type_t *type;
+ ir_initializer_t *initializer;
+ size_t index;
+ declaration_t *compound_entry;
+};
+
+typedef struct type_path_t type_path_t;
+struct type_path_t {
+ type_path_entry_t *path;
+ type_t *top_type;
+ bool invalid;
+};
+
+static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+
+ for(size_t i = 0; i < len; ++i) {
+ const type_path_entry_t *entry = & path->path[i];
+
+ type_t *type = skip_typeref(entry->type);
+ if(is_type_compound(type)) {
+ fprintf(stderr, ".%s", entry->compound_entry->symbol->string);
+ } else if(is_type_array(type)) {
+ fprintf(stderr, "[%u]", entry->index);
+ } else {
+ fprintf(stderr, "-INVALID-");
+ }
+ }
+ fprintf(stderr, " (");
+ print_type(path->top_type);
+ fprintf(stderr, ")");
+}
+
+static type_path_entry_t *get_type_path_top(const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ assert(len > 0);
+ return & path->path[len-1];
+}
+
+static type_path_entry_t *append_to_type_path(type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len+1);
+
+ type_path_entry_t *result = & path->path[len];
+ memset(result, 0, sizeof(result[0]));
+ return result;
+}
+
+static size_t get_compound_size(const compound_type_t *type)
+{
+ declaration_t *declaration = type->declaration;
+ declaration_t *member = declaration->scope.declarations;
+ size_t size = 0;
+ for( ; member != NULL; member = member->next) {
+ ++size;
+ }
+ /* TODO: cache results? */
+
+ return size;
+}
+
+static ir_initializer_t *get_initializer_entry(type_path_t *path)
+{
+ type_t *orig_top_type = path->top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ assert(is_type_compound(top_type) || is_type_array(top_type));
+
+ if(ARR_LEN(path->path) == 0) {
+ return NULL;
+ } else {
+ type_path_entry_t *top = get_type_path_top(path);
+ ir_initializer_t *initializer = top->initializer;
+ return get_initializer_compound_value(initializer, top->index);
+ }
+}
+
+static void descend_into_subtype(type_path_t *path)
+{
+ type_t *orig_top_type = path->top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ assert(is_type_compound(top_type) || is_type_array(top_type));
+
+ ir_initializer_t *initializer = get_initializer_entry(path);
+
+ type_path_entry_t *top = append_to_type_path(path);
+ top->type = top_type;
+
+ size_t len;
+
+ if(is_type_compound(top_type)) {
+ declaration_t *declaration = top_type->compound.declaration;
+ declaration_t *entry = declaration->scope.declarations;
+
+ top->compound_entry = entry;
+ top->index = 0;
+ path->top_type = entry->type;
+ len = get_compound_size(&top_type->compound);
+ } else {
+ assert(is_type_array(top_type));
+ assert(top_type->array.size > 0);
+
+ top->index = 0;
+ path->top_type = top_type->array.element_type;
+ len = top_type->array.size;
+ }
+ if(initializer == NULL
+ || get_initializer_kind(initializer) == IR_INITIALIZER_NULL) {
+ initializer = create_initializer_compound(len);
+ /* we have to set the entry at the 2nd latest path entry... */
+ size_t path_len = ARR_LEN(path->path);
+ assert(path_len >= 1);
+ if(path_len > 1) {
+ type_path_entry_t *entry = & path->path[path_len-2];
+ ir_initializer_t *tinitializer = entry->initializer;
+ set_initializer_compound_value(tinitializer, entry->index,
+ initializer);
+ }
+ }
+ top->initializer = initializer;
+}
+
+static void ascend_from_subtype(type_path_t *path)
+{
+ type_path_entry_t *top = get_type_path_top(path);
+
+ path->top_type = top->type;
+
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len-1);
+}
+
+static void walk_designator(type_path_t *path, const designator_t *designator)
+{
+ /* designators start at current object type */
+ ARR_RESIZE(type_path_entry_t, path->path, 1);
+
+ for( ; designator != NULL; designator = designator->next) {
+ type_path_entry_t *top = get_type_path_top(path);
+ type_t *orig_type = top->type;
+ type_t *type = skip_typeref(orig_type);
+
+ if(designator->symbol != NULL) {
+ assert(is_type_compound(type));
+ size_t index = 0;
+ symbol_t *symbol = designator->symbol;
+
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next, ++index) {
+ if(iter->symbol == symbol) {
+ break;
+ }
+ }
+ assert(iter != NULL);
+
+ top->type = orig_type;
+ top->compound_entry = iter;
+ top->index = index;
+ orig_type = iter->type;
+ } else {
+ expression_t *array_index = designator->array_index;
+ assert(designator->array_index != NULL);
+ assert(is_type_array(type));
+ assert(is_type_valid(array_index->base.type));
+
+ long index = fold_constant(array_index);
+ assert(index >= 0);
+#ifndef NDEBUG
+ if(type->array.size_constant == 1) {
+ long array_size = type->array.size;
+ assert(index < array_size);
+ }
+#endif
+
+ top->type = orig_type;
+ top->index = (size_t) index;
+ orig_type = type->array.element_type;
+ }
+ path->top_type = orig_type;
+
+ if(designator->next != NULL) {
+ descend_into_subtype(path);
+ }
+ }
+
+ path->invalid = false;
+}
+
+static void advance_current_object(type_path_t *path)
+{
+ if(path->invalid) {
+ /* TODO: handle this... */
+ panic("invalid initializer in ast2firm (excessive elements)");
+ return;
+ }
+
+ type_path_entry_t *top = get_type_path_top(path);
+
+ type_t *type = skip_typeref(top->type);
+ if(is_type_union(type)) {
+ top->compound_entry = NULL;
+ } else if(is_type_struct(type)) {
+ declaration_t *entry = top->compound_entry;
+
+ top->index++;
+ entry = entry->next;
+ top->compound_entry = entry;
+ if(entry != NULL) {
+ path->top_type = entry->type;
+ return;
+ }
+ } else {
+ assert(is_type_array(type));
+
+ top->index++;
+ if(!type->array.size_constant || top->index < type->array.size) {
+ return;
+ }
+ }
+
+ /* we're past the last member of the current sub-aggregate, try if we
+ * can ascend in the type hierarchy and continue with another subobject */
+ size_t len = ARR_LEN(path->path);
+
+ if(len > 1) {
+ ascend_from_subtype(path);
+ advance_current_object(path);
+ } else {
+ path->invalid = true;
+ }
+}
+
+
static ir_initializer_t *create_ir_initializer(
- const initializer_t *initializer);
+ const initializer_t *initializer, type_t *type);
static ir_initializer_t *create_ir_initializer_value(
const initializer_value_t *initializer)
return create_initializer_const(value);
}
-static ir_initializer_t *create_ir_initializer_compound(
- const initializer_list_t *initializer)
+static ir_initializer_t *create_ir_initializer_list(
+ const initializer_list_t *initializer, type_t *type)
{
- ir_initializer_t *irinitializer
- = create_initializer_compound(initializer->len);
+ type_path_t path;
+ memset(&path, 0, sizeof(path));
+ path.top_type = type;
+ path.path = NEW_ARR_F(type_path_entry_t, 0);
+
+ descend_into_subtype(&path);
for(size_t i = 0; i < initializer->len; ++i) {
- const initializer_t *sub_initializer = initializer->initializers[i];
- ir_initializer_t *sub_irinitializer
- = create_ir_initializer(sub_initializer);
+ const initializer_t *sub_initializer = initializer->initializers[i];
- set_initializer_compound_value(irinitializer, i, sub_irinitializer);
+ if(sub_initializer->kind == INITIALIZER_DESIGNATOR) {
+ walk_designator(&path, sub_initializer->designator.designator);
+ continue;
+ }
+
+ if(sub_initializer->kind == INITIALIZER_VALUE) {
+ /* we might have to descend into types until we're at a scalar
+ * type */
+ while(true) {
+ type_t *orig_top_type = path.top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ if(is_type_scalar(top_type))
+ break;
+ descend_into_subtype(&path);
+ }
+ }
+
+ ir_initializer_t *sub_irinitializer
+ = create_ir_initializer(sub_initializer, path.top_type);
+
+ size_t path_len = ARR_LEN(path.path);
+ assert(path_len >= 1);
+ type_path_entry_t *entry = & path.path[path_len-1];
+ ir_initializer_t *tinitializer = entry->initializer;
+ set_initializer_compound_value(tinitializer, entry->index,
+ sub_irinitializer);
+
+ advance_current_object(&path);
}
- return irinitializer;
+ assert(ARR_LEN(path.path) >= 1);
+ ir_initializer_t *result = path.path[0].initializer;
+ DEL_ARR_F(path.path);
+
+ return result;
}
static ir_initializer_t *create_ir_initializer_string(
const initializer_string_t *initializer)
{
- size_t len = initializer->string.size;
+ size_t len = initializer->string.size;
ir_initializer_t *irinitializer = create_initializer_compound(len);
const char *string = initializer->string.begin;
ir_mode *mode = get_type_mode(ir_type_const_char);
for(size_t i = 0; i < len; ++i) {
- tarval *tv = new_tarval_from_long(string[i], mode);
+ tarval *tv = new_tarval_from_long(string[i], mode);
ir_initializer_t *char_initializer = create_initializer_tarval(tv);
set_initializer_compound_value(irinitializer, i, char_initializer);
static ir_initializer_t *create_ir_initializer_wide_string(
const initializer_wide_string_t *initializer)
{
- size_t len = initializer->string.size;
+ size_t len = initializer->string.size;
ir_initializer_t *irinitializer = create_initializer_compound(len);
const wchar_rep_t *string = initializer->string.begin;
return irinitializer;
}
-static ir_initializer_t *create_ir_initializer(const initializer_t *initializer)
+static ir_initializer_t *create_ir_initializer(
+ const initializer_t *initializer, type_t *type)
{
- switch((initializer_kind_t) initializer->kind) {
+ switch(initializer->kind) {
case INITIALIZER_STRING:
return create_ir_initializer_string(&initializer->string);
return create_ir_initializer_wide_string(&initializer->wide_string);
case INITIALIZER_LIST:
- return create_ir_initializer_compound(&initializer->list);
+ return create_ir_initializer_list(&initializer->list, type);
case INITIALIZER_VALUE:
return create_ir_initializer_value(&initializer->value);
+
+ case INITIALIZER_DESIGNATOR:
+ panic("unexpected designator initializer found");
}
panic("unknown initializer");
}
-static void create_initializer_local_variable_entity(declaration_t *declaration)
+
+static void create_local_initializer(initializer_t *initializer, dbg_info *dbgi,
+ ir_entity *entity, type_t *type)
{
- initializer_t *initializer = declaration->init.initializer;
- dbg_info *dbgi = get_dbg_info(&declaration->source_position);
- ir_entity *entity = declaration->v.entity;
- ir_node *memory = get_store();
- ir_node *nomem = new_NoMem();
- ir_node *frame = get_irg_frame(current_ir_graph);
- ir_node *addr = new_d_simpleSel(dbgi, nomem, frame, entity);
+ ir_node *memory = get_store();
+ ir_node *nomem = new_NoMem();
+ ir_node *frame = get_irg_frame(current_ir_graph);
+ ir_node *addr = new_d_simpleSel(dbgi, nomem, frame, entity);
if(initializer->kind == INITIALIZER_VALUE) {
initializer_value_t *initializer_value = &initializer->value;
ir_node *value = expression_to_firm(initializer_value->value);
- type_t *type = skip_typeref(declaration->type);
+ type = skip_typeref(type);
assign_value(dbgi, addr, type, value);
return;
}
/* create a "template" entity which is copied to the entity on the stack */
ident *const id = unique_ident("initializer");
- ir_type *const irtype = get_ir_type(declaration->type);
+ ir_type *const irtype = get_ir_type(type);
ir_type *const global_type = get_glob_type();
ir_entity *const init_entity = new_d_entity(global_type, id, irtype, dbgi);
set_entity_ld_ident(init_entity, id);
ir_graph *const old_current_ir_graph = current_ir_graph;
current_ir_graph = get_const_code_irg();
- ir_initializer_t *irinitializer = create_ir_initializer(initializer);
+ ir_initializer_t *irinitializer = create_ir_initializer(initializer, type);
set_entity_initializer(init_entity, irinitializer);
assert(current_ir_graph == get_const_code_irg());
set_store(copyb_mem);
}
+static void create_initializer_local_variable_entity(declaration_t *declaration)
+{
+ initializer_t *initializer = declaration->init.initializer;
+ dbg_info *dbgi = get_dbg_info(&declaration->source_position);
+ ir_entity *entity = declaration->v.entity;
+ type_t *type = declaration->type;
+ create_local_initializer(initializer, dbgi, entity, type);
+}
+
static void create_declaration_initializer(declaration_t *declaration)
{
initializer_t *initializer = declaration->init.initializer;
|| declaration_kind == DECLARATION_KIND_GLOBAL_VARIABLE);
ir_entity *entity = declaration->v.entity;
- ir_initializer_t *irinitializer = create_ir_initializer(initializer);
+ ir_initializer_t *irinitializer
+ = create_ir_initializer(initializer, declaration->type);
set_entity_variability(entity, variability_initialized);
set_entity_initializer(entity, irinitializer);
}
}
-void exit_ast2firm(void)
+static void init_ir_types(void)
{
- obstack_free(&asm_obst, NULL);
-}
+ static int ir_types_initialized = 0;
+ if(ir_types_initialized)
+ return;
+ ir_types_initialized = 1;
-void translation_unit_to_firm(translation_unit_t *unit)
-{
type_const_char = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_CONST);
type_void = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
type_int = make_atomic_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
type in firm */
type_void->base.firm_type = ir_type_void;
+}
+void exit_ast2firm(void)
+{
+ obstack_free(&asm_obst, NULL);
+}
+
+void translation_unit_to_firm(translation_unit_t *unit)
+{
/* just to be sure */
continue_label = NULL;
break_label = NULL;
current_switch_cond = NULL;
+ init_ir_types();
+
scope_to_firm(&unit->scope);
}
EXPR_CHAR_CONST,
EXPR_STRING_LITERAL,
EXPR_WIDE_STRING_LITERAL,
+ EXPR_COMPOUND_LITERAL,
EXPR_CALL,
EXPR_CONDITIONAL,
EXPR_SELECT,
wide_string_t value;
};
+struct compound_literal_expression_t {
+ expression_base_t base;
+ type_t *type;
+ initializer_t *initializer;
+};
+
struct builtin_symbol_expression_t {
expression_base_t base;
symbol_t *symbol;
};
struct designator_t {
- symbol_t *symbol;
- expression_t *array_access;
- designator_t *next;
+ source_position_t source_position;
+ symbol_t *symbol;
+ expression_t *array_index;
+ designator_t *next;
};
struct offsetof_expression_t {
const_expression_t conste;
string_literal_expression_t string;
wide_string_literal_expression_t wide_string;
+ compound_literal_expression_t compound_literal;
builtin_symbol_expression_t builtin_symbol;
builtin_constant_expression_t builtin_constant;
builtin_prefetch_expression_t builtin_prefetch;
INITIALIZER_VALUE,
INITIALIZER_LIST,
INITIALIZER_STRING,
- INITIALIZER_WIDE_STRING
+ INITIALIZER_WIDE_STRING,
+ INITIALIZER_DESIGNATOR
} initializer_kind_t;
struct initializer_base_t {
};
struct initializer_value_t {
- initializer_base_t initializer;
+ initializer_base_t base;
expression_t *value;
};
struct initializer_list_t {
- initializer_base_t initializer;
+ initializer_base_t base;
size_t len;
initializer_t *initializers[];
};
struct initializer_string_t {
- initializer_base_t initializer;
+ initializer_base_t base;
string_t string;
};
struct initializer_wide_string_t {
- initializer_base_t initializer;
+ initializer_base_t base;
wide_string_t string;
};
+struct initializer_designator_t {
+ initializer_base_t base;
+ designator_t *designator;
+};
+
union initializer_t {
initializer_kind_t kind;
initializer_base_t base;
initializer_list_t list;
initializer_string_t string;
initializer_wide_string_t wide_string;
+ initializer_designator_t designator;
};
typedef enum {
parse_line_directive();
break;
case '\n':
- /* NULL directive, see § 6.10.7 */
+ /* NULL directive, see § 6.10.7 */
break;
default:
parse_error("invalid preprocessor directive");
static goto_statement_t *goto_last = NULL;
static label_statement_t *label_first = NULL;
static label_statement_t *label_last = NULL;
-static struct obstack temp_obst;
+static struct obstack temp_obst;
/** The current source position. */
#define HERE token.source_position
[EXPR_CHAR_CONST] = sizeof(const_expression_t),
[EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t),
[EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t),
+ [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t),
[EXPR_CALL] = sizeof(call_expression_t),
[EXPR_UNARY_FIRST] = sizeof(unary_expression_t),
[EXPR_BINARY_FIRST] = sizeof(binary_expression_t),
[INITIALIZER_VALUE] = sizeof(initializer_value_t),
[INITIALIZER_STRING] = sizeof(initializer_string_t),
[INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t),
- [INITIALIZER_LIST] = sizeof(initializer_list_t)
+ [INITIALIZER_LIST] = sizeof(initializer_list_t),
+ [INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t)
};
assert(kind < sizeof(sizes) / sizeof(*sizes));
assert(sizes[kind] != 0);
}
#define expect(expected) \
+ do { \
if(UNLIKELY(token.type != (expected))) { \
parse_error_expected(NULL, (expected), 0); \
eat_statement(); \
return NULL; \
} \
- next_token();
+ next_token(); \
+ } while(0)
#define expect_block(expected) \
+ do { \
if(UNLIKELY(token.type != (expected))) { \
parse_error_expected(NULL, (expected), 0); \
eat_block(); \
return NULL; \
} \
- next_token();
+ next_token(); \
+ } while(0)
#define expect_void(expected) \
+ do { \
if(UNLIKELY(token.type != (expected))) { \
parse_error_expected(NULL, (expected), 0); \
eat_statement(); \
return; \
} \
- next_token();
+ next_token(); \
+ } while(0)
static void set_scope(scope_t *new_scope)
{
return orig_type_left;
}
- if (is_type_compound(type_left) && is_type_compound(type_right)) {
+ if ((is_type_compound(type_left) && is_type_compound(type_right))
+ || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
type_t *const unqual_type_left = get_unqualified_type(type_left);
type_t *const unqual_type_right = get_unqualified_type(type_right);
if (types_compatible(unqual_type_left, unqual_type_right)) {
;
}
-#if 0
static designator_t *parse_designation(void)
{
- if(token.type != '[' && token.type != '.')
- return NULL;
-
designator_t *result = NULL;
designator_t *last = NULL;
- while(1) {
+ while(true) {
designator_t *designator;
switch(token.type) {
case '[':
designator = allocate_ast_zero(sizeof(designator[0]));
+ designator->source_position = token.source_position;
next_token();
- designator->array_access = parse_constant_expression();
+ designator->array_index = parse_constant_expression();
expect(']');
break;
case '.':
designator = allocate_ast_zero(sizeof(designator[0]));
+ designator->source_position = token.source_position;
next_token();
if(token.type != T_IDENTIFIER) {
parse_error_expected("while parsing designator",
last = designator;
}
}
-#endif
static initializer_t *initializer_from_string(array_type_t *type,
const string_t *const string)
return initializer;
}
-static initializer_t *initializer_from_expression(type_t *type,
+static initializer_t *initializer_from_expression(type_t *orig_type,
expression_t *expression)
{
/* TODO check that expression is a constant expression */
/* § 6.7.8.14/15 char array may be initialized by string literals */
- type_t *const expr_type = expression->base.type;
+ type_t *type = skip_typeref(orig_type);
+ type_t *expr_type_orig = expression->base.type;
+ type_t *expr_type = skip_typeref(expr_type_orig);
if (is_type_array(type) && expr_type->kind == TYPE_POINTER) {
array_type_t *const array_type = &type->array;
type_t *const element_type = skip_typeref(array_type->element_type);
return result;
}
-static initializer_t *parse_sub_initializer(type_t *type,
- expression_t *expression);
-
-static initializer_t *parse_sub_initializer_elem(type_t *type)
+static initializer_t *parse_scalar_initializer(type_t *type)
{
- if(token.type == '{') {
- return parse_sub_initializer(type, NULL);
+ /* there might be extra {} hierarchies */
+ int braces = 0;
+ while(token.type == '{') {
+ next_token();
+ if(braces == 0) {
+ warningf(HERE, "extra curly braces around scalar initializer");
+ }
+ braces++;
}
- expression_t *expression = parse_assignment_expression();
- return parse_sub_initializer(type, expression);
-}
+ expression_t *expression = parse_assignment_expression();
+ initializer_t *initializer = initializer_from_expression(type, expression);
-static bool had_initializer_brace_warning;
+ if(initializer == NULL) {
+ errorf(expression->base.source_position,
+ "expression '%E' doesn't match expected type '%T'",
+ expression, type);
+ /* TODO */
+ return NULL;
+ }
-static void skip_designator(void)
-{
- while(1) {
- if(token.type == '.') {
+ bool additional_warning_displayed = false;
+ while(braces > 0) {
+ if(token.type == ',') {
next_token();
- if(token.type == T_IDENTIFIER)
- next_token();
- } else if(token.type == '[') {
- next_token();
- parse_constant_expression();
- if(token.type == ']')
- next_token();
- } else {
- break;
}
+ if(token.type != '}') {
+ if(!additional_warning_displayed) {
+ warningf(HERE, "additional elements in scalar initializer");
+ additional_warning_displayed = true;
+ }
+ }
+ eat_block();
+ braces--;
}
+
+ return initializer;
}
-static initializer_t *parse_sub_initializer(type_t *type,
- expression_t *expression)
+typedef struct type_path_entry_t type_path_entry_t;
+struct type_path_entry_t {
+ type_t *type;
+ union {
+ size_t index;
+ declaration_t *compound_entry;
+ } v;
+};
+
+typedef struct type_path_t type_path_t;
+struct type_path_t {
+ type_path_entry_t *path;
+ type_t *top_type;
+ bool invalid;
+};
+
+static __attribute__((unused)) void debug_print_type_path(const type_path_t *path)
{
- if(is_type_scalar(type)) {
- /* there might be extra {} hierarchies */
- if(token.type == '{') {
- next_token();
- if(!had_initializer_brace_warning) {
- warningf(HERE, "braces around scalar initializer");
- had_initializer_brace_warning = true;
- }
- initializer_t *result = parse_sub_initializer(type, NULL);
- if(token.type == ',') {
- next_token();
- /* TODO: warn about excessive elements */
- }
- expect_block('}');
- return result;
- }
+ size_t len = ARR_LEN(path->path);
- if(expression == NULL) {
- expression = parse_assignment_expression();
+ if(path->invalid) {
+ fprintf(stderr, "invalid path");
+ return;
+ }
+
+ for(size_t i = 0; i < len; ++i) {
+ const type_path_entry_t *entry = & path->path[i];
+
+ type_t *type = skip_typeref(entry->type);
+ if(is_type_compound(type)) {
+ fprintf(stderr, ".%s", entry->v.compound_entry->symbol->string);
+ } else if(is_type_array(type)) {
+ fprintf(stderr, "[%u]", entry->v.index);
+ } else {
+ fprintf(stderr, "-INVALID-");
}
- return initializer_from_expression(type, expression);
}
+ fprintf(stderr, " (");
+ print_type(path->top_type);
+ fprintf(stderr, ")");
+}
- /* does the expression match the currently looked at object to initialize */
- if(expression != NULL) {
- initializer_t *result = initializer_from_expression(type, expression);
- if(result != NULL)
- return result;
+static type_path_entry_t *get_type_path_top(const type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ assert(len > 0);
+ return & path->path[len-1];
+}
+
+static type_path_entry_t *append_to_type_path(type_path_t *path)
+{
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len+1);
+
+ type_path_entry_t *result = & path->path[len];
+ memset(result, 0, sizeof(result[0]));
+ return result;
+}
+
+static void descend_into_subtype(type_path_t *path)
+{
+ type_t *orig_top_type = path->top_type;
+ type_t *top_type = skip_typeref(orig_top_type);
+
+ assert(is_type_compound(top_type) || is_type_array(top_type));
+
+ type_path_entry_t *top = append_to_type_path(path);
+ top->type = top_type;
+
+ if(is_type_compound(top_type)) {
+ declaration_t *declaration = top_type->compound.declaration;
+ declaration_t *entry = declaration->scope.declarations;
+
+ top->v.compound_entry = entry;
+ path->top_type = entry->type;
+ } else {
+ assert(is_type_array(top_type));
+
+ top->v.index = 0;
+ path->top_type = top_type->array.element_type;
}
+}
- bool read_paren = false;
- if(token.type == '{') {
- next_token();
- read_paren = true;
+static void ascend_from_subtype(type_path_t *path)
+{
+ type_path_entry_t *top = get_type_path_top(path);
+
+ path->top_type = top->type;
+
+ size_t len = ARR_LEN(path->path);
+ ARR_RESIZE(type_path_entry_t, path->path, len-1);
+}
+
+static void ascend_to(type_path_t *path, size_t top_path_level)
+{
+ size_t len = ARR_LEN(path->path);
+ assert(len >= top_path_level);
+
+ while(len > top_path_level) {
+ ascend_from_subtype(path);
+ len = ARR_LEN(path->path);
}
+}
- /* descend into subtype */
- initializer_t *result = NULL;
- initializer_t **elems;
- if(is_type_array(type)) {
- if(token.type == '.') {
- errorf(HERE,
- "compound designator in initializer for array type '%T'",
- type);
- skip_designator();
- }
+static bool walk_designator(type_path_t *path, const designator_t *designator,
+ bool used_in_offsetof)
+{
+ for( ; designator != NULL; designator = designator->next) {
+ type_path_entry_t *top = get_type_path_top(path);
+ type_t *orig_type = top->type;
- type_t *const element_type = skip_typeref(type->array.element_type);
+ type_t *type = skip_typeref(orig_type);
- initializer_t *sub;
- had_initializer_brace_warning = false;
+ if(designator->symbol != NULL) {
+ symbol_t *symbol = designator->symbol;
+ if(!is_type_compound(type)) {
+ if(is_type_valid(type)) {
+ errorf(designator->source_position,
+ "'.%Y' designator used for non-compound type '%T'",
+ symbol, orig_type);
+ }
+ goto failed;
+ }
- if(token.type == '{') {
- sub = parse_sub_initializer(element_type, NULL);
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next) {
+ if(iter->symbol == symbol) {
+ break;
+ }
+ }
+ if(iter == NULL) {
+ errorf(designator->source_position,
+ "'%T' has no member named '%Y'", orig_type, symbol);
+ goto failed;
+ }
+ if(used_in_offsetof) {
+ type_t *real_type = skip_typeref(iter->type);
+ if(real_type->kind == TYPE_BITFIELD) {
+ errorf(designator->source_position,
+ "offsetof designator '%Y' may not specify bitfield",
+ symbol);
+ goto failed;
+ }
+ }
+
+ top->type = orig_type;
+ top->v.compound_entry = iter;
+ orig_type = iter->type;
} else {
- if(expression == NULL) {
- expression = parse_assignment_expression();
-
- /* 6.7.8.14 + 15: we can have an optional {} around the string
- * literal */
- if(read_paren && (expression->kind == EXPR_STRING_LITERAL
- || expression->kind == EXPR_WIDE_STRING_LITERAL)) {
- initializer_t *result
- = initializer_from_expression(type, expression);
- if(result != NULL) {
- expect_block('}');
- return result;
+ expression_t *array_index = designator->array_index;
+ assert(designator->array_index != NULL);
+
+ if(!is_type_array(type)) {
+ if(is_type_valid(type)) {
+ errorf(designator->source_position,
+ "[%E] designator used for non-array type '%T'",
+ array_index, orig_type);
+ }
+ goto failed;
+ }
+ if(!is_type_valid(array_index->base.type)) {
+ goto failed;
+ }
+
+ long index = fold_constant(array_index);
+ if(!used_in_offsetof) {
+ if(index < 0) {
+ errorf(designator->source_position,
+ "array index [%E] must be positive", array_index);
+ goto failed;
+ }
+ if(type->array.size_constant == true) {
+ long array_size = type->array.size;
+ if(index >= array_size) {
+ errorf(designator->source_position,
+ "designator [%E] (%d) exceeds array size %d",
+ array_index, index, array_size);
+ goto failed;
}
}
}
- sub = parse_sub_initializer(element_type, expression);
+ top->type = orig_type;
+ top->v.index = (size_t) index;
+ orig_type = type->array.element_type;
}
+ path->top_type = orig_type;
- /* didn't match the subtypes -> try the parent type */
- if(sub == NULL) {
- assert(!read_paren);
- return NULL;
+ if(designator->next != NULL) {
+ descend_into_subtype(path);
}
+ }
- elems = NEW_ARR_F(initializer_t*, 0);
- ARR_APP1(initializer_t*, elems, sub);
+ path->invalid = false;
+ return true;
- while(true) {
- if(token.type == '}')
- break;
- expect_block(',');
- if(token.type == '}')
- break;
+failed:
+ return false;
+}
- sub = parse_sub_initializer_elem(element_type);
- if(sub == NULL) {
- /* TODO error, do nicer cleanup */
- errorf(HERE, "member initializer didn't match");
- DEL_ARR_F(elems);
- return NULL;
- }
- ARR_APP1(initializer_t*, elems, sub);
+static void advance_current_object(type_path_t *path, size_t top_path_level)
+{
+ if(path->invalid)
+ return;
+
+ type_path_entry_t *top = get_type_path_top(path);
+
+ type_t *type = skip_typeref(top->type);
+ if(is_type_union(type)) {
+ /* in unions only the first element is initialized */
+ top->v.compound_entry = NULL;
+ } else if(is_type_struct(type)) {
+ declaration_t *entry = top->v.compound_entry;
+
+ entry = entry->next;
+ top->v.compound_entry = entry;
+ if(entry != NULL) {
+ path->top_type = entry->type;
+ return;
}
} else {
- assert(is_type_compound(type));
- scope_t *const scope = &type->compound.declaration->scope;
+ assert(is_type_array(type));
- if(token.type == '[') {
- errorf(HERE,
- "array designator in initializer for compound type '%T'",
- type);
- skip_designator();
+ top->v.index++;
+
+ if(!type->array.size_constant || top->v.index < type->array.size) {
+ return;
}
+ }
- declaration_t *first = scope->declarations;
- if(first == NULL)
- return NULL;
- type_t *first_type = first->type;
- first_type = skip_typeref(first_type);
+ /* we're past the last member of the current sub-aggregate, try if we
+ * can ascend in the type hierarchy and continue with another subobject */
+ size_t len = ARR_LEN(path->path);
- initializer_t *sub;
- had_initializer_brace_warning = false;
- if(expression == NULL) {
- sub = parse_sub_initializer_elem(first_type);
- } else {
- sub = parse_sub_initializer(first_type, expression);
+ if(len > top_path_level) {
+ ascend_from_subtype(path);
+ advance_current_object(path, top_path_level);
+ } else {
+ path->invalid = true;
+ }
+}
+
+static void skip_initializers(void)
+{
+ if(token.type == '{')
+ next_token();
+
+ while(token.type != '}') {
+ if(token.type == T_EOF)
+ return;
+ if(token.type == '{') {
+ eat_block();
+ continue;
}
+ next_token();
+ }
+}
+
+static initializer_t *parse_sub_initializer(type_path_t *path,
+ type_t *outer_type, size_t top_path_level)
+{
+ type_t *orig_type = path->top_type;
+ type_t *type = skip_typeref(orig_type);
- /* didn't match the subtypes -> try our parent type */
- if(sub == NULL) {
- assert(!read_paren);
- return NULL;
+ /* we can't do usefull stuff if we didn't even parse the type. Skip the
+ * initializers in this case. */
+ if(!is_type_valid(type)) {
+ skip_initializers();
+ return NULL;
+ }
+
+ initializer_t **initializers = NEW_ARR_F(initializer_t*, 0);
+
+ while(true) {
+ designator_t *designator = NULL;
+ if(token.type == '.' || token.type == '[') {
+ designator = parse_designation();
+
+ /* reset path to toplevel, evaluate designator from there */
+ ascend_to(path, top_path_level);
+ if(!walk_designator(path, designator, false)) {
+ /* can't continue after designation error */
+ goto end_error;
+ }
+
+ initializer_t *designator_initializer
+ = allocate_initializer_zero(INITIALIZER_DESIGNATOR);
+ designator_initializer->designator.designator = designator;
+ ARR_APP1(initializer_t*, initializers, designator_initializer);
}
- elems = NEW_ARR_F(initializer_t*, 0);
- ARR_APP1(initializer_t*, elems, sub);
+ initializer_t *sub;
- declaration_t *iter = first->next;
- for( ; iter != NULL; iter = iter->next) {
- if(iter->symbol == NULL)
- continue;
- if(iter->namespc != NAMESPACE_NORMAL)
- continue;
+ if(token.type == '{') {
+ if(is_type_scalar(type)) {
+ sub = parse_scalar_initializer(type);
+ } else {
+ eat('{');
+ descend_into_subtype(path);
- if(token.type == '}')
- break;
- expect_block(',');
- if(token.type == '}')
- break;
+ sub = parse_sub_initializer(path, orig_type, top_path_level+1);
- type_t *iter_type = iter->type;
- iter_type = skip_typeref(iter_type);
+ ascend_from_subtype(path);
- sub = parse_sub_initializer_elem(iter_type);
- if(sub == NULL) {
- /* TODO error, do nicer cleanup */
- errorf(HERE, "member initializer didn't match");
- DEL_ARR_F(elems);
- return NULL;
+ expect_block('}');
+ }
+ } else {
+ /* must be an expression */
+ expression_t *expression = parse_assignment_expression();
+
+ /* handle { "string" } special case */
+ if((expression->kind == EXPR_STRING_LITERAL
+ || expression->kind == EXPR_WIDE_STRING_LITERAL)
+ && outer_type != NULL) {
+ sub = initializer_from_expression(outer_type, expression);
+ if(sub != NULL) {
+ if(token.type == ',') {
+ next_token();
+ }
+ if(token.type != '}') {
+ warningf(HERE, "excessive elements in initializer for type '%T'",
+ orig_type);
+ }
+ /* TODO: eat , ... */
+ return sub;
+ }
+ }
+
+ /* descend into subtypes until expression matches type */
+ while(true) {
+ orig_type = path->top_type;
+ type = skip_typeref(orig_type);
+
+ sub = initializer_from_expression(orig_type, expression);
+ if(sub != NULL) {
+ break;
+ }
+ if(!is_type_valid(type)) {
+ goto end_error;
+ }
+ if(is_type_scalar(type)) {
+ errorf(expression->base.source_position,
+ "expression '%E' doesn't match expected type '%T'",
+ expression, orig_type);
+ goto end_error;
+ }
+
+ descend_into_subtype(path);
}
- ARR_APP1(initializer_t*, elems, sub);
}
- }
+ ARR_APP1(initializer_t*, initializers, sub);
- int len = ARR_LEN(elems);
- size_t elems_size = sizeof(initializer_t*) * len;
+ if(token.type == '}') {
+ break;
+ }
+ expect(',');
+ if(token.type == '}') {
+ break;
+ }
+ advance_current_object(path, top_path_level);
+ }
- initializer_list_t *init = allocate_ast_zero(sizeof(init[0]) + elems_size);
+ size_t len = ARR_LEN(initializers);
+ size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]);
+ initializer_t *result = allocate_ast_zero(size);
+ result->kind = INITIALIZER_LIST;
+ result->list.len = len;
+ memcpy(&result->list.initializers, initializers,
+ len * sizeof(initializers[0]));
- init->initializer.kind = INITIALIZER_LIST;
- init->len = len;
- memcpy(init->initializers, elems, elems_size);
- DEL_ARR_F(elems);
+ ascend_to(path, top_path_level);
- result = (initializer_t*) init;
+ /* TODO: if(is_global && !is_constant(...)) { error } */
- if(read_paren) {
- if(token.type == ',')
- next_token();
- expect('}');
- }
return result;
+
+end_error:
+ skip_initializers();
+ DEL_ARR_F(initializers);
+ ascend_to(path, top_path_level);
+ return NULL;
}
static initializer_t *parse_initializer(type_t *const orig_type)
}
if(is_type_scalar(type)) {
- /* § 6.7.8.11 */
- eat('{');
+ /* TODO: § 6.7.8.11; eat {} without warning */
- expression_t *expression = parse_assignment_expression();
- result = initializer_from_expression(type, expression);
+ result = parse_scalar_initializer(type);
if(token.type == ',')
next_token();
- expect('}');
return result;
+ } else if(token.type == '{') {
+ next_token();
+
+ type_path_t path;
+ memset(&path, 0, sizeof(path));
+ path.top_type = orig_type;
+ path.path = NEW_ARR_F(type_path_entry_t, 0);
+
+ descend_into_subtype(&path);
+
+ result = parse_sub_initializer(&path, orig_type, 1);
+
+ DEL_ARR_F(path.path);
+
+ expect('}');
} else {
- result = parse_sub_initializer(type, NULL);
+ /* TODO ... */
}
return result;
parsed_array_t *parsed_array = (parsed_array_t*) iter;
type_t *array_type = allocate_type_zero(TYPE_ARRAY, (source_position_t){NULL, 0});
- array_type->base.qualifiers = parsed_array->type_qualifiers;
- array_type->array.element_type = type;
- array_type->array.is_static = parsed_array->is_static;
- array_type->array.is_variable = parsed_array->is_variable;
- array_type->array.size = parsed_array->size;
+ expression_t *size_expression = parsed_array->size;
+
+ array_type->base.qualifiers = parsed_array->type_qualifiers;
+ array_type->array.element_type = type;
+ array_type->array.is_static = parsed_array->is_static;
+ array_type->array.is_variable = parsed_array->is_variable;
+ array_type->array.size_expression = size_expression;
+
+ if(size_expression != NULL &&
+ is_constant_expression(size_expression)) {
+ array_type->array.size_constant = true;
+ array_type->array.size
+ = fold_constant(size_expression);
+ }
type_t *skipped_type = skip_typeref(type);
if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) {
if(is_type_array(type) && initializer != NULL) {
array_type_t *array_type = &type->array;
- if(array_type->size == NULL) {
- expression_t *cnst = allocate_expression_zero(EXPR_CONST);
-
- cnst->base.type = type_size_t;
-
+ if(array_type->size_expression == NULL) {
+ size_t size;
switch (initializer->kind) {
case INITIALIZER_LIST: {
- cnst->conste.v.int_value = initializer->list.len;
+ /* TODO */
+ size = initializer->list.len;
break;
}
case INITIALIZER_STRING: {
- cnst->conste.v.int_value = initializer->string.string.size;
+ size = initializer->string.string.size;
break;
}
case INITIALIZER_WIDE_STRING: {
- cnst->conste.v.int_value = initializer->wide_string.string.size;
+ size = initializer->wide_string.string.size;
break;
}
- default:
+ default: {
panic("invalid initializer type");
+ break;
+ }
}
- array_type->size = cnst;
- array_type->has_implicit_size = true;
+ expression_t *cnst = allocate_expression_zero(EXPR_CONST);
+ cnst->base.type = type_size_t;
+ cnst->conste.v.int_value = size;
+
+ array_type->size_expression = cnst;
+ array_type->size_constant = true;
+ array_type->size = size;
}
}
/* TODO check if explicit cast is allowed and issue warnings/errors */
}
-static expression_t *parse_cast(void)
+static expression_t *parse_compound_literal(type_t *type)
{
- expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+ expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
+
+ expression->compound_literal.type = type;
+ expression->compound_literal.initializer = parse_initializer(type);
+ expression->base.type = automatic_type_conversion(type);
- cast->base.source_position = token.source_position;
+ return expression;
+}
+
+static expression_t *parse_cast(void)
+{
+ source_position_t source_position = token.source_position;
type_t *type = parse_typename();
expect(')');
+
+ if(token.type == '{') {
+ return parse_compound_literal(type);
+ }
+
+ expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
+ cast->base.source_position = source_position;
+
expression_t *value = parse_sub_expression(20);
check_cast_allowed(value, type);
static designator_t *parse_designator(void)
{
- designator_t *result = allocate_ast_zero(sizeof(result[0]));
+ designator_t *result = allocate_ast_zero(sizeof(result[0]));
+ result->source_position = HERE;
if(token.type != T_IDENTIFIER) {
parse_error_expected("while parsing member designator",
eat_paren();
return NULL;
}
- designator_t *designator = allocate_ast_zero(sizeof(result[0]));
- designator->symbol = token.v.symbol;
+ designator_t *designator = allocate_ast_zero(sizeof(result[0]));
+ designator->source_position = HERE;
+ designator->symbol = token.v.symbol;
next_token();
last_designator->next = designator;
}
if(token.type == '[') {
next_token();
- designator_t *designator = allocate_ast_zero(sizeof(result[0]));
- designator->array_access = parse_expression();
- if(designator->array_access == NULL) {
+ designator_t *designator = allocate_ast_zero(sizeof(result[0]));
+ designator->source_position = HERE;
+ designator->array_index = parse_expression();
+ if(designator->array_index == NULL) {
eat_paren();
return NULL;
}
expression->base.type = type_size_t;
expect('(');
- expression->offsetofe.type = parse_typename();
+ type_t *type = parse_typename();
expect(',');
- expression->offsetofe.designator = parse_designator();
+ designator_t *designator = parse_designator();
expect(')');
+ expression->offsetofe.type = type;
+ expression->offsetofe.designator = designator;
+
+ type_path_t path;
+ memset(&path, 0, sizeof(path));
+ path.top_type = type;
+ path.path = NEW_ARR_F(type_path_entry_t, 0);
+
+ descend_into_subtype(&path);
+
+ if(!walk_designator(&path, designator, true)) {
+ return create_invalid_expression();
+ }
+
+ DEL_ARR_F(path.path);
+
return expression;
}
case EXPR_VA_START: return true;
case EXPR_VA_ARG: return true;
case EXPR_STATEMENT: return true; // TODO
+ case EXPR_COMPOUND_LITERAL: return false;
case EXPR_UNARY_NEGATE: return false;
case EXPR_UNARY_PLUS: return false;
type_t *revert_automatic_type_conversion(const expression_t *expression);
declaration_t *expr_is_variable(const expression_t *expression);
-/* some builtin types */
-extern type_t *type_wchar_t;
-extern type_t *type_size_t;
-extern type_t *type_ptrdiff_t;
-extern type_t *type_wchar_ptr_t;
-
#endif
--- /dev/null
+int puts(const char *str);
+
+struct bla {
+ int a;
+ float b;
+ char c[20];
+};
+
+int main(void)
+{
+ struct bla a;
+ a = (struct bla) { 4, 5.2, "Hello" };
+ puts(a.c);
+ return 0;
+}
--- /dev/null
+struct A {
+ int k;
+ struct B {
+ int a, b[4];
+ } blup[2];
+ struct C {
+ int a : 5;
+ int b : 3;
+ } c;
+};
+
+int k = __builtin_offsetof(struct A, blup[2].b[3]);
+
+int main(void)
+{
+ return k == 0;
+}
--- /dev/null
+struct A {
+ int k;
+ struct B {
+ int a, b[4];
+ } blup[2];
+ struct C {
+ int a : 5;
+ int b : 3;
+ } c;
+};
+
+int k = __builtin_offsetof(struct A, blup[2].b[3]);
+int k2 = __builtin_offsetof(struct A, c.b);
+
+int main(void)
+{
+ return k == 0;
+}
fputs("static ", out);
}
print_type_qualifiers(type->type.qualifiers);
- if(type->size != NULL
+ if(type->size_expression != NULL
&& (print_implicit_array_size || !type->has_implicit_size)) {
- print_expression(type->size);
+ print_expression(type->size_expression);
}
fputc(']', out);
intern_print_type_post(type->element_type, false);
return true;
case TYPE_ARRAY:
- return type->array.size == NULL;
+ return type->array.size_expression == NULL;
case TYPE_ATOMIC:
return type->atomic.akind == ATOMIC_TYPE_VOID;
if(!types_compatible(element_type1, element_type2))
return false;
- if(array1->size != NULL && array2->size != NULL) {
- /* TODO: check if size expression evaluate to the same value
- * if they are constant */
- }
+ if(!array1->size_constant || !array2->size_constant)
+ return true;
- return true;
+ return array1->size == array2->size;
}
/**
struct array_type_t {
type_base_t type;
type_t *element_type;
- expression_t *size;
+ expression_t *size_expression;
+ size_t size;
unsigned is_static : 1;
unsigned is_variable : 1;
unsigned has_implicit_size : 1;
+ unsigned size_constant : 1;
};
struct function_parameter_t {
return type->kind == TYPE_FUNCTION;
}
+static inline bool is_type_union(const type_t *type)
+{
+ assert(!is_typeref(type));
+ return type->kind == TYPE_COMPOUND_UNION;
+}
+
+static inline bool is_type_struct(const type_t *type)
+{
+ assert(!is_typeref(type));
+ return type->kind == TYPE_COMPOUND_STRUCT;
+}
+
+static inline bool is_type_builtin(const type_t *type)
+{
+ assert(!is_typeref(type));
+ return type->kind == TYPE_BUILTIN;
+}
+
static inline bool is_type_compound(const type_t *type)
{
assert(!is_typeref(type));
extern type_t *type_uintmax_t;
extern type_t *type_uptrdiff_t;
extern type_t *type_wchar_t;
+extern type_t *type_wchar_ptr_t;
extern type_t *type_wint_t;
extern type_t *type_intmax_t_ptr;