#include "lang_features.h"
#include "walk_statements.h"
#include "warning.h"
+#include "printer.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
#include "adt/array.h"
static scope_t *current_scope = NULL;
/** Point to the current function declaration if inside a function. */
static function_t *current_function = NULL;
+static entity_t *current_entity = NULL;
static entity_t *current_init_decl = NULL;
static switch_statement_t *current_switch = NULL;
static statement_t *current_loop = NULL;
static label_statement_t **label_anchor = NULL;
/** current translation unit. */
static translation_unit_t *unit = NULL;
-/** true if we are in a type property context (evaluation only for type. */
+/** true if we are in a type property context (evaluation only for type) */
static bool in_type_prop = false;
-/** true in we are in a __extension__ context. */
+/** true if we are in an __extension__ context. */
static bool in_gcc_extension = false;
static struct obstack temp_obst;
static entity_t *anonymous_entity;
#define POP_PARENT ((void)(current_parent = prev_parent))
/** special symbol used for anonymous entities. */
-static const symbol_t *sym_anonymous = NULL;
+static symbol_t *sym_anonymous = NULL;
/** The token anchor set */
static unsigned char token_anchor_set[T_LAST_TOKEN];
static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
declarator_flags_t flags);
-static entity_t *record_entity(entity_t *entity, bool is_definition);
-
static void semantic_comparison(binary_expression_t *expression);
-static void create_gnu_builtins(void);
-static void create_microsoft_intrinsics(void);
-
#define STORAGE_CLASSES \
STORAGE_CLASSES_NO_EXTERN \
case T_extern:
case T_throw: \
case T_true:
-/**
- * Allocate an AST node with given size and
- * initialize all fields with zero.
- */
-static void *allocate_ast_zero(size_t size)
-{
- void *res = allocate_ast(size);
- memset(res, 0, size);
- return res;
-}
-
-/**
- * Returns the size of an entity node.
- *
- * @param kind the entity kind
- */
-static size_t get_entity_struct_size(entity_kind_t kind)
-{
- static const size_t sizes[] = {
- [ENTITY_VARIABLE] = sizeof(variable_t),
- [ENTITY_PARAMETER] = sizeof(parameter_t),
- [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t),
- [ENTITY_FUNCTION] = sizeof(function_t),
- [ENTITY_TYPEDEF] = sizeof(typedef_t),
- [ENTITY_STRUCT] = sizeof(compound_t),
- [ENTITY_UNION] = sizeof(compound_t),
- [ENTITY_ENUM] = sizeof(enum_t),
- [ENTITY_ENUM_VALUE] = sizeof(enum_value_t),
- [ENTITY_LABEL] = sizeof(label_t),
- [ENTITY_LOCAL_LABEL] = sizeof(label_t),
- [ENTITY_NAMESPACE] = sizeof(namespace_t)
- };
- assert(kind < lengthof(sizes));
- assert(sizes[kind] != 0);
- return sizes[kind];
-}
-
-/**
- * Allocate an entity of given kind and initialize all
- * fields with zero.
- *
- * @param kind the kind of the entity to allocate
- */
-static entity_t *allocate_entity_zero(entity_kind_t kind)
-{
- size_t size = get_entity_struct_size(kind);
- entity_t *entity = allocate_ast_zero(size);
- entity->kind = kind;
- return entity;
-}
-
/**
* Returns the size of a statement node.
*
return allocate_statement_zero(STATEMENT_EMPTY);
}
-/**
- * Returns the size of a type node.
- *
- * @param kind the type kind
- */
-static size_t get_type_struct_size(type_kind_t kind)
-{
- static const size_t sizes[] = {
- [TYPE_ATOMIC] = sizeof(atomic_type_t),
- [TYPE_COMPLEX] = sizeof(complex_type_t),
- [TYPE_IMAGINARY] = sizeof(imaginary_type_t),
- [TYPE_BITFIELD] = sizeof(bitfield_type_t),
- [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t),
- [TYPE_COMPOUND_UNION] = sizeof(compound_type_t),
- [TYPE_ENUM] = sizeof(enum_type_t),
- [TYPE_FUNCTION] = sizeof(function_type_t),
- [TYPE_POINTER] = sizeof(pointer_type_t),
- [TYPE_ARRAY] = sizeof(array_type_t),
- [TYPE_BUILTIN] = sizeof(builtin_type_t),
- [TYPE_TYPEDEF] = sizeof(typedef_type_t),
- [TYPE_TYPEOF] = sizeof(typeof_type_t),
- };
- assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1);
- assert(kind <= TYPE_TYPEOF);
- assert(sizes[kind] != 0);
- return sizes[kind];
-}
-
-/**
- * Allocate a type node of given kind and initialize all
- * fields with zero.
- *
- * @param kind type kind to allocate
- */
-static type_t *allocate_type_zero(type_kind_t kind)
-{
- size_t size = get_type_struct_size(kind);
- type_t *res = obstack_alloc(type_obst, size);
- memset(res, 0, size);
- res->base.kind = kind;
-
- return res;
-}
-
static function_parameter_t *allocate_parameter(type_t *const type)
{
- function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param));
+ function_parameter_t *const param
+ = obstack_alloc(type_obst, sizeof(*param));
memset(param, 0, sizeof(*param));
param->type = type;
return param;
#endif
}
+static inline bool next_if(int const type)
+{
+ if (token.type == type) {
+ next_token();
+ return true;
+ } else {
+ return false;
+ }
+}
+
/**
* Return the next token with a given lookahead.
*/
static void eat_block(void)
{
eat_until_matching_token('{');
- if (token.type == '}')
- next_token();
+ next_if('}');
}
#define eat(token_type) (assert(token.type == (token_type)), next_token())
parse_error_expected(NULL, (expected), NULL); \
add_anchor_token(expected); \
eat_until_anchor(); \
- if (token.type == expected) \
- next_token(); \
+ next_if((expected)); \
rem_anchor_token(expected); \
goto error_label; \
} \
/* §6.2.3:1 24) There is only one name space for tags even though three are
* possible. */
static entity_t *get_tag(symbol_t const *const symbol,
- entity_kind_tag_t const kind)
+ entity_kind_tag_t const kind)
{
entity_t *entity = get_entity(symbol, NAMESPACE_TAG);
if (entity != NULL && entity->kind != kind) {
*/
static attribute_argument_t *parse_attribute_arguments(void)
{
- if (token.type == ')')
- return NULL;
-
- attribute_argument_t *first = NULL;
- attribute_argument_t *last = NULL;
- while (true) {
+ attribute_argument_t *first = NULL;
+ attribute_argument_t **anchor = &first;
+ if (token.type != ')') do {
attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument));
/* is it an identifier */
}
/* append argument */
- if (last == NULL) {
- first = argument;
- } else {
- last->next = argument;
- }
- last = argument;
-
- if (token.type == ',') {
- next_token();
- continue;
- }
- expect(')', end_error);
- break;
- }
+ *anchor = argument;
+ anchor = &argument->next;
+ } while (next_if(','));
+ expect(')', end_error);
return first;
attribute_t *attribute = allocate_attribute_zero(kind);
/* parse arguments */
- if (token.type == '(') {
- next_token();
+ if (next_if('('))
attribute->a.arguments = parse_attribute_arguments();
- }
return attribute;
static attribute_t *parse_attribute_gnu(void)
{
- attribute_t *first = NULL;
- attribute_t *last = NULL;
+ attribute_t *first = NULL;
+ attribute_t **anchor = &first;
eat(T___attribute__);
expect('(', end_error);
expect('(', end_error);
- if (token.type == ')') {
- next_token();
- expect(')', end_error);
- return first;
- }
-
- while (true) {
+ if (token.type != ')') do {
attribute_t *attribute = parse_attribute_gnu_single();
if (attribute == NULL)
goto end_error;
- if (last == NULL) {
- first = attribute;
- } else {
- last->next = attribute;
- }
- last = attribute;
-
- if (token.type == ')') {
- next_token();
- break;
- }
- expect(',', end_error);
- }
+ *anchor = attribute;
+ anchor = &attribute->next;
+ } while (next_if(','));
+ expect(')', end_error);
expect(')', end_error);
end_error:
/** Parse attributes. */
static attribute_t *parse_attributes(attribute_t *first)
{
- attribute_t *last = first;
- while (true) {
- if (last != NULL) {
- while (last->next != NULL)
- last = last->next;
- }
+ attribute_t **anchor = &first;
+ for (;;) {
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
attribute_t *attribute;
switch (token.type) {
return first;
}
- if (last == NULL) {
- first = attribute;
- } else {
- last->next = attribute;
- }
- last = attribute;
+ *anchor = attribute;
+ anchor = &attribute->next;
}
}
static designator_t *parse_designation(void)
{
- designator_t *result = NULL;
- designator_t *last = NULL;
+ designator_t *result = NULL;
+ designator_t **anchor = &result;
- while (true) {
+ for (;;) {
designator_t *designator;
switch (token.type) {
case '[':
}
assert(designator != NULL);
- if (last != NULL) {
- last->next = designator;
- } else {
- result = designator;
- }
- last = designator;
+ *anchor = designator;
+ anchor = &designator->next;
}
end_error:
return NULL;
{
/* there might be extra {} hierarchies */
int braces = 0;
- if (token.type == '{') {
+ if (next_if('{')) {
if (warning.other)
warningf(HERE, "extra curly braces around scalar initializer");
do {
++braces;
- next_token();
- } while (token.type == '{');
+ } while (next_if('{'));
}
expression_t *expression = parse_assignment_expression();
mark_vars_read(expression, NULL);
if (must_be_constant && !is_initializer_constant(expression)) {
errorf(&expression->base.source_position,
- "Initialisation expression '%E' is not constant",
+ "initialisation expression '%E' is not constant",
expression);
}
bool additional_warning_displayed = false;
while (braces > 0) {
- if (token.type == ',') {
- next_token();
- }
+ next_if(',');
if (token.type != '}') {
if (!additional_warning_displayed && warning.other) {
warningf(HERE, "additional elements in scalar initializer");
*/
static void skip_initializers(void)
{
- if (token.type == '{')
- next_token();
+ next_if('{');
while (token.type != '}') {
if (token.type == T_EOF)
if (type == NULL) {
/* we are already outside, ... */
+ if (outer_type == NULL)
+ goto error_parse_next;
type_t *const outer_type_skip = skip_typeref(outer_type);
if (is_type_compound(outer_type_skip) &&
!outer_type_skip->compound.compound->complete) {
&& outer_type != NULL) {
sub = initializer_from_expression(outer_type, expression);
if (sub != NULL) {
- if (token.type == ',') {
- next_token();
- }
+ next_if(',');
if (token.type != '}' && warning.other) {
warningf(HERE, "excessive elements in initializer for type '%T'",
orig_type);
} else {
scope->entities = entity;
}
- scope->last_entity = entity;
+ entity->base.parent_entity = current_entity;
+ scope->last_entity = entity;
}
static compound_t *parse_compound_type_specifier(bool is_struct)
{
- if (is_struct) {
- eat(T_struct);
- } else {
- eat(T_union);
- }
+ eat(is_struct ? T_struct : T_union);
symbol_t *symbol = NULL;
compound_t *compound = NULL;
entity->base.source_position = token.source_position;
next_token();
- if (token.type == '=') {
- next_token();
+ if (next_if('=')) {
expression_t *value = parse_constant_expression();
value = create_implicit_cast(value, enum_type);
}
record_entity(entity, false);
-
- if (token.type != ',')
- break;
- next_token();
- } while (token.type != '}');
+ } while (next_if(',') && token.type != '}');
rem_anchor_token('}');
expect('}', end_error);
static type_t *parse_enum_specifier(void)
{
- entity_t *entity;
- symbol_t *symbol;
+ entity_t *entity;
+ symbol_t *symbol;
eat(T_enum);
- if (token.type == T_IDENTIFIER) {
- symbol = token.v.symbol;
- next_token();
+ switch (token.type) {
+ case T_IDENTIFIER:
+ symbol = token.v.symbol;
+ next_token();
- entity = get_tag(symbol, ENTITY_ENUM);
- if (entity != NULL) {
- if (entity->base.parent_scope != current_scope &&
- (token.type == '{' || token.type == ';')) {
- /* we're in an inner scope and have a definition. Shadow
- * existing definition in outer scope */
- entity = NULL;
- } else if (entity->enume.complete && token.type == '{') {
- errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
- symbol, &entity->base.source_position);
+ entity = get_tag(symbol, ENTITY_ENUM);
+ if (entity != NULL) {
+ if (entity->base.parent_scope != current_scope &&
+ (token.type == '{' || token.type == ';')) {
+ /* we're in an inner scope and have a definition. Shadow
+ * existing definition in outer scope */
+ entity = NULL;
+ } else if (entity->enume.complete && token.type == '{') {
+ errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
+ symbol, &entity->base.source_position);
+ }
}
- }
- } else if (token.type != '{') {
- parse_error_expected("while parsing enum type specifier",
- T_IDENTIFIER, '{', NULL);
- return NULL;
- } else {
- entity = NULL;
- symbol = NULL;
+ break;
+
+ case '{':
+ entity = NULL;
+ symbol = NULL;
+ break;
+
+ default:
+ parse_error_expected("while parsing enum type specifier",
+ T_IDENTIFIER, '{', NULL);
+ return NULL;
}
if (entity == NULL) {
bool old_gcc_extension = in_gcc_extension;
in_type_prop = true;
- while (token.type == T___extension__) {
+ while (next_if(T___extension__)) {
/* This can be a prefix to a typename or an expression. */
- next_token();
in_gcc_extension = true;
}
switch (token.type) {
attribute_property_argument_t *property
= allocate_ast_zero(sizeof(*property));
- while (true) {
+ do {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing property declspec",
T_IDENTIFIER, NULL);
property->get_symbol = token.v.symbol;
}
next_token();
- if (token.type == ')')
- break;
- expect(',', end_error);
- }
+ } while (next_if(','));
attribute->a.property = property;
static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
{
attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
- if (token.type == T_restrict) {
+ if (next_if(T_restrict)) {
kind = ATTRIBUTE_MS_RESTRICT;
- next_token();
} else if (token.type == T_IDENTIFIER) {
const char *name = token.v.symbol->string;
next_token();
}
/* parse arguments */
- if (token.type == '(') {
- next_token();
+ if (next_if('('))
attribute->a.arguments = parse_attribute_arguments();
- }
return attribute;
}
expect('(', end_error);
- if (token.type == ')') {
- next_token();
+ if (next_if(')'))
return NULL;
- }
add_anchor_token(')');
- attribute_t *last = first;
- while (true) {
- if (last != NULL) {
- while (last->next != NULL)
- last = last->next;
- }
+ attribute_t **anchor = &first;
+ do {
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
attribute_t *attribute
= parse_microsoft_extended_decl_modifier_single();
if (attribute == NULL)
goto end_error;
- if (last == NULL) {
- first = attribute;
- } else {
- last->next = attribute;
- }
- last = attribute;
-
- if (token.type == ')') {
- break;
- }
- expect(',', end_error);
- }
+ *anchor = attribute;
+ anchor = &attribute->next;
+ } while (next_if(','));
rem_anchor_token(')');
expect(')', end_error);
end_error:
specifiers->type = type_error_type;
- return;
}
static type_qualifiers_t parse_type_qualifiers(void)
if (scope != NULL)
append_entity(scope, entity);
-
- if (token.type != ',') {
- break;
- }
- next_token();
- } while (token.type == T_IDENTIFIER);
+ } while (next_if(',') && token.type == T_IDENTIFIER);
}
static entity_t *parse_parameter(void)
if (has_parameters()) {
function_parameter_t **anchor = &type->parameters;
- for (;;) {
+ do {
switch (token.type) {
case T_DOTDOTDOT:
next_token();
default:
goto parameters_finished;
}
- if (token.type != ',') {
- goto parameters_finished;
- }
- next_token();
- }
+ } while (next_if(','));
}
memset(array, 0, sizeof(*array));
cons->kind = CONSTRUCT_ARRAY;
- if (token.type == T_static) {
+ if (next_if(T_static))
array->is_static = true;
- next_token();
- }
type_qualifiers_t type_qualifiers = parse_type_qualifiers();
- if (type_qualifiers != 0) {
- if (token.type == T_static) {
+ if (type_qualifiers != 0 && next_if(T_static))
array->is_static = true;
- next_token();
- }
- }
array->type_qualifiers = type_qualifiers;
if (token.type == '*' && look_ahead(1)->type == ']') {
break;
case T__based: {
-#if 0
- source_position_t const pos = *HERE;
- next_token();
- expect('(', end_error);
- add_anchor_token(')');
- based = parse_microsoft_based();
- rem_anchor_token(')');
- expect(')', end_error);
- if (token.type != '*') {
- if (token.type == T__based) {
- errorf(&pos, "__based type modifier specified more than once");
- } else if (warning.other) {
- warningf(&pos,
- "__based does not precede a pointer declarator, ignored");
- }
- continue;
- }
-#else
- panic("based currently disabled");
-#endif
+ panic("based not supported anymore");
/* FALLTHROUGH */
}
}
ptr_operator_end: ;
-#if 0
- modifiers |= env->modifiers;
- env->modifiers = modifiers;
-#endif
-
construct_type_t *inner_types = NULL;
switch (token.type) {
return NULL;
}
-static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type)
+static type_t *construct_declarator_type(construct_type_t *construct_list,
+ type_t *type)
{
construct_type_t *iter = construct_list;
for (; iter != NULL; iter = iter->base.next) {
attribute_t *attributes = parse_attributes(env.attributes);
/* append (shared) specifier attribute behind attributes of this
- declarator */
- if (attributes != NULL) {
- attribute_t *last = attributes;
- while (last->next != NULL)
- last = last->next;
- last->next = specifiers->attributes;
- } else {
- attributes = specifiers->attributes;
- }
+ * declarator */
+ attribute_t **anchor = &attributes;
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
+ *anchor = specifiers->attributes;
entity_t *entity;
if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
storage_class_t storage_class = specifiers->storage_class;
entity->declaration.declared_storage_class = storage_class;
- if (storage_class == STORAGE_CLASS_NONE && current_scope != file_scope)
+ if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
storage_class = STORAGE_CLASS_AUTO;
entity->declaration.storage_class = storage_class;
}
return false;
}
+static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
+{
+ for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) {
+ if (attributes_equal(tattr, attr))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * test wether new_list contains any attributes not included in old_list
+ */
+static bool has_new_attributes(const attribute_t *old_list,
+ const attribute_t *new_list)
+{
+ for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) {
+ if (!contains_attribute(old_list, attr))
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Merge in attributes from an attribute list (probably from a previous
+ * declaration with the same name). Warning: destroys the old structure
+ * of the attribute list - don't reuse attributes after this call.
+ */
+static void merge_in_attributes(declaration_t *decl, attribute_t *attributes)
+{
+ attribute_t *next;
+ for (attribute_t *attr = attributes; attr != NULL; attr = next) {
+ next = attr->next;
+ if (contains_attribute(decl->attributes, attr))
+ continue;
+
+ /* move attribute to new declarations attributes list */
+ attr->next = decl->attributes;
+ decl->attributes = attr;
+ }
+}
+
/**
* record entities for the NAMESPACE_NORMAL, and produce error messages/warnings
* for various problems that occur for multiple definitions
*/
-static entity_t *record_entity(entity_t *entity, const bool is_definition)
+entity_t *record_entity(entity_t *entity, const bool is_definition)
{
const symbol_t *const symbol = entity->base.symbol;
const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
if (old_storage_class == STORAGE_CLASS_EXTERN &&
new_storage_class == STORAGE_CLASS_EXTERN) {
-warn_redundant_declaration:
- if (!is_definition &&
+
+warn_redundant_declaration: ;
+ bool has_new_attrs
+ = has_new_attributes(prev_decl->attributes,
+ decl->attributes);
+ if (has_new_attrs) {
+ merge_in_attributes(decl, prev_decl->attributes);
+ } else if (!is_definition &&
warning.redundant_decls &&
is_type_valid(prev_type) &&
strcmp(previous_entity->base.source_position.input_name,
"<builtin>") != 0) {
warningf(pos,
- "redundant declaration for '%Y' (declared %P)",
- symbol, &previous_entity->base.source_position);
+ "redundant declaration for '%Y' (declared %P)",
+ symbol, &previous_entity->base.source_position);
}
} else if (current_function == NULL) {
if (old_storage_class != STORAGE_CLASS_STATIC &&
new_storage_class == STORAGE_CLASS_STATIC) {
errorf(pos,
- "static declaration of '%Y' follows non-static declaration (declared %P)",
- symbol, &previous_entity->base.source_position);
+ "static declaration of '%Y' follows non-static declaration (declared %P)",
+ symbol, &previous_entity->base.source_position);
} else if (old_storage_class == STORAGE_CLASS_EXTERN) {
prev_decl->storage_class = STORAGE_CLASS_NONE;
prev_decl->declared_storage_class = STORAGE_CLASS_NONE;
check_variable_type_complete(entity);
- if (token.type != ',')
+ if (!next_if(','))
break;
- eat(',');
add_anchor_token('=');
ndeclaration = parse_declarator(specifiers, flags);
break;
}
- case STATEMENT_CONTINUE: {
- statement_t *parent = stmt;
- for (;;) {
+ case STATEMENT_CONTINUE:
+ for (statement_t *parent = stmt;;) {
parent = parent->base.parent;
if (parent == NULL) /* continue not within loop */
return;
default: break;
}
}
- }
- case STATEMENT_BREAK: {
- statement_t *parent = stmt;
- for (;;) {
+ case STATEMENT_BREAK:
+ for (statement_t *parent = stmt;;) {
parent = parent->base.parent;
if (parent == NULL) /* break not within loop/switch */
return;
}
found_break_parent:
break;
- }
case STATEMENT_GOTO:
if (stmt->gotos.expression) {
/* parse function body */
int label_stack_top = label_top();
function_t *old_current_function = current_function;
+ entity_t *old_current_entity = current_entity;
current_function = function;
+ current_entity = (entity_t*) function;
current_parent = NULL;
goto_first = NULL;
assert(current_parent == NULL);
assert(current_function == function);
+ assert(current_entity == (entity_t*) function);
+ current_entity = old_current_entity;
current_function = old_current_function;
label_pop_to(label_stack_top);
}
type_t *skipped_type = skip_typeref(base_type);
if (!is_type_integer(skipped_type)) {
errorf(HERE, "bitfield base type '%T' is not an integer type",
- base_type);
+ base_type);
bit_size = 0;
} else {
bit_size = get_type_size(base_type) * 8;
static void parse_compound_declarators(compound_t *compound,
const declaration_specifiers_t *specifiers)
{
- while (true) {
+ do {
entity_t *entity;
if (token.type == ':') {
type_t *type = make_bitfield_type(base_type, size,
&source_position, NULL);
- attribute_t *attributes = parse_attributes(NULL);
- if (attributes != NULL) {
- attribute_t *last = attributes;
- while (last->next != NULL)
- last = last->next;
- last->next = specifiers->attributes;
- } else {
- attributes = specifiers->attributes;
- }
+ attribute_t *attributes = parse_attributes(NULL);
+ attribute_t **anchor = &attributes;
+ while (*anchor != NULL)
+ anchor = &(*anchor)->next;
+ *anchor = specifiers->attributes;
entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER);
entity->base.namespc = NAMESPACE_NORMAL;
type_t *type = skip_typeref(orig_type);
if (is_type_function(type)) {
errorf(&entity->base.source_position,
- "compound member '%Y' must not have function type '%T'",
+ "compound member '%Y' must not have function type '%T'",
entity->base.symbol, orig_type);
} else if (is_type_incomplete(type)) {
/* §6.7.2.1:16 flexible array member */
token.type != ';' ||
look_ahead(1)->type != '}') {
errorf(&entity->base.source_position,
- "compound member '%Y' has incomplete type '%T'",
+ "compound member '%Y' has incomplete type '%T'",
entity->base.symbol, orig_type);
}
}
append_entity(&compound->members, entity);
}
}
-
- if (token.type != ',')
- break;
- next_token();
- }
+ } while (next_if(','));
expect(';', end_error);
end_error:
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
- if (specifiers.storage_class != STORAGE_CLASS_NONE ||
- specifiers.thread_local) {
+ if (specifiers.storage_class != STORAGE_CLASS_NONE
+ || specifiers.thread_local) {
/* TODO: improve error message, user does probably not know what a
* storage class is...
*/
return entity;
}
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- */
-static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1,
- type_t *argument_type2)
-{
- function_parameter_t *const parameter2 = allocate_parameter(argument_type2);
- function_parameter_t *const parameter1 = allocate_parameter(argument_type1);
- parameter1->next = parameter2;
-
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = parameter1;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type) function type if not
- * already exists.
- *
- * @param return_type the return type
- * @param argument_type the argument type
- */
-static type_t *make_function_1_type(type_t *return_type, type_t *argument_type)
-{
- function_parameter_t *const parameter = allocate_parameter(argument_type);
-
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = parameter;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(argument_type, ...) function type if not
- * already exists.
- *
- * @param return_type the return type
- * @param argument_type the argument type
- */
-static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type)
-{
- function_parameter_t *const parameter = allocate_parameter(argument_type);
-
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = parameter;
- type->function.variadic = true;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type the return type
- */
-static type_t *make_function_0_type(type_t *return_type)
-{
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = NULL;
-
- return identify_new_type(type);
-}
-
-/**
- * Creates a NO_RETURN return_type (func)(void) function type if not
- * already exists.
- *
- * @param return_type the return type
- */
-static type_t *make_function_0_type_noreturn(type_t *return_type)
-{
- type_t *type = allocate_type_zero(TYPE_FUNCTION);
- type->function.return_type = return_type;
- type->function.parameters = NULL;
- type->function.modifiers |= DM_NORETURN;
- return identify_new_type(type);
-}
-
/**
* Performs automatic type cast as described in §6.3.2.1.
*
}
}
-static expression_t *parse_reference(void)
+/**
+ * Find an entity matching a symbol in a scope.
+ * Uses current scope if scope is NULL
+ */
+static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
+ namespace_tag_t namespc)
{
- symbol_t *const symbol = token.v.symbol;
+ if (scope == NULL) {
+ return get_entity(symbol, namespc);
+ }
- entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
+ /* we should optimize here, if scope grows above a certain size we should
+ construct a hashmap here... */
+ entity_t *entity = scope->entities;
+ for ( ; entity != NULL; entity = entity->base.next) {
+ if (entity->base.symbol == symbol && entity->base.namespc == namespc)
+ break;
+ }
+
+ return entity;
+}
+
+static entity_t *parse_qualified_identifier(void)
+{
+ /* namespace containing the symbol */
+ symbol_t *symbol;
+ source_position_t pos;
+ const scope_t *lookup_scope = NULL;
+
+ if (next_if(T_COLONCOLON))
+ lookup_scope = &unit->scope;
+
+ entity_t *entity;
+ while (true) {
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL);
+ return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
+ }
+ symbol = token.v.symbol;
+ pos = *HERE;
+ next_token();
+
+ /* lookup entity */
+ entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
+
+ if (!next_if(T_COLONCOLON))
+ break;
+
+ switch (entity->kind) {
+ case ENTITY_NAMESPACE:
+ lookup_scope = &entity->namespacee.members;
+ break;
+ case ENTITY_STRUCT:
+ case ENTITY_UNION:
+ case ENTITY_CLASS:
+ lookup_scope = &entity->compound.members;
+ break;
+ default:
+ errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)",
+ symbol, get_entity_kind_name(entity->kind));
+ goto end_error;
+ }
+ }
if (entity == NULL) {
- if (!strict_mode && look_ahead(1)->type == '(') {
+ if (!strict_mode && token.type == '(') {
/* an implicitly declared function */
if (warning.error_implicit_function_declaration) {
- errorf(HERE, "implicit declaration of function '%Y'", symbol);
+ errorf(&pos, "implicit declaration of function '%Y'", symbol);
} else if (warning.implicit_function_declaration) {
- warningf(HERE, "implicit declaration of function '%Y'", symbol);
+ warningf(&pos, "implicit declaration of function '%Y'", symbol);
}
- entity = create_implicit_function(symbol, HERE);
+ entity = create_implicit_function(symbol, &pos);
} else {
- errorf(HERE, "unknown identifier '%Y' found.", symbol);
+ errorf(&pos, "unknown identifier '%Y' found.", symbol);
entity = create_error_entity(symbol, ENTITY_VARIABLE);
}
}
- type_t *orig_type;
+ return entity;
+
+end_error:
+ /* skip further qualifications */
+ while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+
+ return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
+}
+static expression_t *parse_reference(void)
+{
+ entity_t *entity = parse_qualified_identifier();
+
+ type_t *orig_type;
if (is_declaration(entity)) {
orig_type = entity->declaration.type;
} else if (entity->kind == ENTITY_ENUM_VALUE) {
}
if (entity->base.parent_scope != file_scope
- && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth)
- && is_type_valid(orig_type) && !is_type_function(orig_type)) {
+ && (current_function != NULL
+ && entity->base.parent_scope->depth < current_function->parameters.depth)
+ && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) {
if (entity->kind == ENTITY_VARIABLE) {
/* access of a variable from an outer function */
entity->variable.address_taken = true;
entity->declaration.type, entity->base.symbol);
}
- next_token();
return expression;
}
designator_t *last_designator = result;
while (true) {
- if (token.type == '.') {
- next_token();
+ if (next_if('.')) {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing member designator",
T_IDENTIFIER, NULL);
last_designator = designator;
continue;
}
- if (token.type == '[') {
- next_token();
+ if (next_if('[')) {
add_anchor_token(']');
designator_t *designator = allocate_ast_zero(sizeof(result[0]));
designator->source_position = *HERE;
add_anchor_token(')');
add_anchor_token(',');
- if (token.type != ')') {
- while (true) {
- (void)parse_assignment_expression();
- if (token.type != ',')
- break;
- next_token();
- }
- }
+ if (token.type != ')') do {
+ (void)parse_assignment_expression();
+ } while (next_if(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
case T___noop: return parse_noop_expression();
/* Gracefully handle type names while parsing expressions. */
+ case T_COLONCOLON:
+ return parse_reference();
case T_IDENTIFIER:
if (!is_typedef_symbol(token.v.symbol)) {
return parse_reference();
if (token.type != ')') {
call_argument_t **anchor = &call->arguments;
- for (;;) {
+ do {
call_argument_t *argument = allocate_ast_zero(sizeof(*argument));
argument->expression = parse_assignment_expression();
*anchor = argument;
anchor = &argument->next;
-
- if (token.type != ',')
- break;
- next_token();
- }
+ } while (next_if(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
eat(T_delete);
- if (token.type == '[') {
- next_token();
+ if (next_if('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
expect(']', end_error);
end_error:;
return true;
default: {
- type_t *type = skip_typeref(expression->base.type);
- return
- /* ISO/IEC 14882:1998(E) §3.10:3 */
- is_type_reference(type) ||
- /* Claim it is an lvalue, if the type is invalid. There was a parse
- * error before, which maybe prevented properly recognizing it as
- * lvalue. */
- !is_type_valid(type);
+ type_t *type = skip_typeref(expression->base.type);
+ return
+ /* ISO/IEC 14882:1998(E) §3.10:3 */
+ is_type_reference(type) ||
+ /* Claim it is an lvalue, if the type is invalid. There was a parse
+ * error before, which maybe prevented properly recognizing it as
+ * lvalue. */
+ !is_type_valid(type);
}
}
}
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
memset(argument, 0, sizeof(argument[0]));
- if (token.type == '[') {
- eat('[');
+ if (next_if('[')) {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing asm argument",
T_IDENTIFIER, NULL);
*anchor = argument;
anchor = &argument->next;
- if (token.type != ',')
+ if (!next_if(','))
break;
- eat(',');
}
return result;
*/
static asm_clobber_t *parse_asm_clobbers(void)
{
- asm_clobber_t *result = NULL;
- asm_clobber_t *last = NULL;
+ asm_clobber_t *result = NULL;
+ asm_clobber_t **anchor = &result;
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;
+ *anchor = clobber;
+ anchor = &clobber->next;
- if (token.type != ',')
+ if (!next_if(','))
break;
- eat(',');
}
return result;
eat(T_asm);
- if (token.type == T_volatile) {
- next_token();
+ if (next_if(T_volatile))
asm_statement->is_volatile = true;
- }
expect('(', end_error);
add_anchor_token(')');
add_anchor_token(':');
asm_statement->asm_text = parse_string_literals();
- if (token.type != ':') {
+ if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
}
- eat(':');
asm_statement->outputs = parse_asm_arguments(true);
- if (token.type != ':') {
+ if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
}
- eat(':');
asm_statement->inputs = parse_asm_arguments(false);
- if (token.type != ':') {
+ if (!next_if(':')) {
rem_anchor_token(':');
goto end_of_asm;
}
rem_anchor_token(':');
- eat(':');
asm_statement->clobbers = parse_asm_clobbers();
}
if (GNU_MODE) {
- if (token.type == T_DOTDOTDOT) {
- next_token();
+ if (next_if(T_DOTDOTDOT)) {
expression_t *const end_range = parse_expression();
statement->case_label.end_range = end_range;
if (!is_constant_expression(end_range)) {
statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
- if (token.type == T_else) {
- next_token();
+ if (next_if(T_else)) {
statement->ifs.false_statement = parse_statement();
} else if (warning.parentheses &&
true_stmt->kind == STATEMENT_IF &&
scope_t *old_scope = scope_push(&statement->fors.scope);
bool old_gcc_extension = in_gcc_extension;
- while (token.type == T___extension__) {
- next_token();
+ while (next_if(T___extension__)) {
in_gcc_extension = true;
}
- if (token.type == ';') {
- next_token();
+ if (next_if(';')) {
} else if (is_declaration_specifier(&token, false)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
eat(T_goto);
- if (GNU_MODE && token.type == '*') {
- next_token();
+ if (GNU_MODE && next_if('*')) {
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
POP_PARENT;
- if (token.type == T___except) {
- eat(T___except);
+ if (next_if(T___except)) {
expect('(', end_error);
add_anchor_token(')');
expression_t *const expr = parse_expression();
rem_anchor_token(')');
expect(')', end_error);
statement->ms_try.final_statement = parse_compound_statement(false);
- } else if (token.type == T__finally) {
- eat(T___finally);
+ } else if (next_if(T__finally)) {
statement->ms_try.final_statement = parse_compound_statement(false);
} else {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
entity_t *begin = NULL, *end = NULL;
- while (true) {
+ do {
if (token.type != T_IDENTIFIER) {
parse_error_expected("while parsing local label declaration",
T_IDENTIFIER, NULL);
environment_push(entity);
}
next_token();
-
- if (token.type != ',')
- break;
- next_token();
- }
+ } while (next_if(','));
eat(';');
end_error:
statement->declaration.declarations_begin = begin;
next_token();
entity = get_entity(symbol, NAMESPACE_NORMAL);
- if (entity != NULL &&
- entity->kind != ENTITY_NAMESPACE &&
- entity->base.parent_scope == current_scope) {
+ if (entity != NULL
+ && entity->kind != ENTITY_NAMESPACE
+ && entity->base.parent_scope == current_scope) {
if (!is_error_entity(entity)) {
error_redefined_as_different_kind(&token.source_position,
entity, ENTITY_NAMESPACE);
size_t const top = environment_top();
scope_t *old_scope = scope_push(&entity->namespacee.members);
+ entity_t *old_current_entity = current_entity;
+ current_entity = entity;
+
expect('{', end_error);
parse_externals();
expect('}', end_error);
end_error:
assert(current_scope == &entity->namespacee.members);
+ assert(current_entity == entity);
+ current_entity = old_current_entity;
scope_pop(old_scope);
environment_pop_to(top);
}
case T___extension__:
/* This can be a prefix to a declaration or an expression statement.
* We simply eat it now and parse the rest with tail recursion. */
- do {
- next_token();
- } while (token.type == T___extension__);
+ while (next_if(T___extension__)) {}
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
statement = intern_parse_statement();
}
current_linkage = new_linkage;
- if (token.type == '{') {
- next_token();
+ if (next_if('{')) {
parse_externals();
expect('}', end_error);
} else {
error_count = 0;
warning_count = 0;
- type_set_output(stderr);
- ast_set_output(stderr);
+ print_to_file(stderr);
assert(unit == NULL);
unit = allocate_ast_zero(sizeof(unit[0]));
incomplete_arrays = NULL;
}
-/**
- * create a builtin function.
- */
-static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type)
-{
- symbol_t *symbol = symbol_table_insert(name);
- entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION);
- entity->declaration.storage_class = STORAGE_CLASS_EXTERN;
- entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
- entity->declaration.type = function_type;
- entity->declaration.implicit = true;
- entity->base.symbol = symbol;
- entity->base.source_position = builtin_source_position;
-
- entity->function.btk = kind;
-
- record_entity(entity, /*is_definition=*/false);
- return entity;
-}
-
-
-/**
- * Create predefined gnu builtins.
- */
-static void create_gnu_builtins(void)
-{
-#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b)
-
- GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t));
- GNU_BUILTIN(huge_val, make_function_0_type(type_double));
- GNU_BUILTIN(inf, make_function_0_type(type_double));
- GNU_BUILTIN(inff, make_function_0_type(type_float));
- GNU_BUILTIN(infl, make_function_0_type(type_long_double));
- GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr));
- GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr));
- GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr));
- GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist));
- GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long));
- GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int));
- GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int));
- GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int));
- GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr));
- GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void));
-
-#undef GNU_BUILTIN
-}
-
-/**
- * Create predefined MS intrinsics.
- */
-static void create_microsoft_intrinsics(void)
-{
-#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b)
-
- /* intrinsics for all architectures */
- MS_BUILTIN(_rotl, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int));
- MS_BUILTIN(_rotr, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int));
- MS_BUILTIN(_rotl64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
- MS_BUILTIN(_rotr64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int));
- MS_BUILTIN(_byteswap_ushort, make_function_1_type(type_unsigned_short, type_unsigned_short));
- MS_BUILTIN(_byteswap_ulong, make_function_1_type(type_unsigned_long, type_unsigned_long));
- MS_BUILTIN(_byteswap_uint64, make_function_1_type(type_unsigned_int64, type_unsigned_int64));
-
- MS_BUILTIN(__debugbreak, make_function_0_type(type_void));
- MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr));
- MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr));
- MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int));
-
- /* x86/x64 only */
- MS_BUILTIN(_enable, make_function_0_type(type_void));
- MS_BUILTIN(_disable, make_function_0_type(type_void));
- MS_BUILTIN(__inbyte, make_function_1_type(type_unsigned_char, type_unsigned_short));
- MS_BUILTIN(__inword, make_function_1_type(type_unsigned_short, type_unsigned_short));
- MS_BUILTIN(__indword, make_function_1_type(type_unsigned_long, type_unsigned_short));
- MS_BUILTIN(__outbyte, make_function_2_type(type_void, type_unsigned_short, type_unsigned_char));
- MS_BUILTIN(__outword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_short));
- MS_BUILTIN(__outdword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_long));
- MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void));
- MS_BUILTIN(_BitScanForward, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
- MS_BUILTIN(_BitScanReverse, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long));
- MS_BUILTIN(_InterlockedExchange, make_function_2_type(type_long, type_long_ptr, type_long));
- MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64));
-
- if (machine_size <= 32) {
- MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int));
- MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int));
- } else {
- MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int64));
- MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int64));
- }
-
-#undef MS_BUILTIN
-}
-
/**
* Initialize the parser.
*/