static stack_entry_t *environment_stack = NULL;
static stack_entry_t *label_stack = NULL;
static stack_entry_t *local_label_stack = NULL;
-static scope_t *global_scope = NULL;
+/** The global file scope. */
+static scope_t *file_scope = NULL;
+/** The current scope. */
static scope_t *scope = NULL;
static declaration_t *last_declaration = NULL;
+/** Point to the current function declaration if inside a function. */
static declaration_t *current_function = NULL;
static declaration_t *current_init_decl = NULL;
static switch_statement_t *current_switch = NULL;
*/
static void eat_until_anchor(void)
{
- if (token.type == T_EOF)
- return;
while (token_anchor_set[token.type] == 0) {
if (token.type == '(' || token.type == '{' || token.type == '[')
eat_until_matching_token(token.type);
- if (token.type == T_EOF)
- break;
next_token();
}
}
next_token(); \
} while (0)
-static void set_scope(scope_t *new_scope)
+static void scope_push(scope_t *new_scope)
{
if (scope != NULL) {
scope->last_declaration = last_declaration;
+ new_scope->depth = scope->depth + 1;
}
- scope = new_scope;
+ new_scope->parent = scope;
+ scope = new_scope;
last_declaration = new_scope->last_declaration;
}
+static void scope_pop(void)
+{
+ scope->last_declaration = last_declaration;
+ scope = scope->parent;
+ last_declaration = scope->last_declaration;
+}
+
/**
* Search a symbol in a given namespace and returns its declaration or
* NULL if this symbol was not found.
namespace_t namespc = (namespace_t) declaration->namespc;
/* replace/add declaration into declaration list of the symbol */
- declaration_t *iter = symbol->declaration;
- if (iter == NULL) {
- symbol->declaration = declaration;
- } else {
- declaration_t *iter_last = NULL;
- for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
- /* replace an entry? */
- if (iter->namespc == namespc) {
- if (iter_last == NULL) {
- symbol->declaration = declaration;
- } else {
- iter_last->symbol_next = declaration;
- }
- declaration->symbol_next = iter->symbol_next;
- break;
- }
- }
- if (iter == NULL) {
- assert(iter_last->symbol_next == NULL);
- iter_last->symbol_next = declaration;
+ declaration_t **anchor;
+ declaration_t *iter;
+ for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+ iter = *anchor;
+ if (iter == NULL)
+ break;
+
+ /* replace an entry? */
+ if (iter->namespc == namespc) {
+ declaration->symbol_next = iter->symbol_next;
+ break;
}
}
+ *anchor = declaration;
/* remember old declaration */
stack_entry_t entry;
namespace_t namespc = (namespace_t)entry->namespc;
/* replace/remove declaration */
- declaration_t *declaration = symbol->declaration;
- assert(declaration != NULL);
- if (declaration->namespc == namespc) {
- if (old_declaration == NULL) {
- symbol->declaration = declaration->symbol_next;
- } else {
- symbol->declaration = old_declaration;
- }
- } else {
- declaration_t *iter_last = declaration;
- declaration_t *iter = declaration->symbol_next;
- for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
- /* replace an entry? */
- if (iter->namespc == namespc) {
- assert(iter_last != NULL);
- iter_last->symbol_next = old_declaration;
- if (old_declaration != NULL) {
- old_declaration->symbol_next = iter->symbol_next;
- }
- break;
- }
- }
+ declaration_t **anchor;
+ declaration_t *iter;
+ for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+ iter = *anchor;
assert(iter != NULL);
+ /* replace an entry? */
+ if (iter->namespc == namespc)
+ break;
}
+
+ /* Because of scopes and appending other namespaces to the end of
+ * the list, this must hold. */
+ assert((old_declaration != NULL ? old_declaration->symbol_next : NULL) == iter->symbol_next);
+ *anchor = old_declaration;
}
ARR_SHRINKLEN(*stack_ptr, (int) new_top);
decl->source_position = *HERE;
decl->declared_storage_class = storage_class;
decl->storage_class =
- storage_class != STORAGE_CLASS_NONE || scope == global_scope ?
+ storage_class != STORAGE_CLASS_NONE || scope == file_scope ?
storage_class : STORAGE_CLASS_AUTO;
decl->symbol = symbol;
decl->implicit = true;
type->compound.declaration = parse_compound_type_specifier(false);
if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
- break;
finish_union_type(&type->compound);
+ break;
}
case T_enum:
type = parse_enum_specifier();
}
}
-static declaration_t *parse_identifier_list(void)
+/**
+ * Parses an K&R identifier list and return a list of declarations.
+ *
+ * @param last points to the last declaration in the list
+ * @return the list of declarations
+ */
+static declaration_t *parse_identifier_list(declaration_t **last)
{
declaration_t *declarations = NULL;
declaration_t *last_declaration = NULL;
next_token();
} while (token.type == T_IDENTIFIER);
+ *last = last_declaration;
return declarations;
}
return declaration;
}
-static declaration_t *parse_parameters(function_type_t *type)
+/**
+ * Parses a function type parameter list and return a list of declarations.
+ *
+ * @param last point to the last element of the list
+ * @return the parameter list
+ */
+static declaration_t *parse_parameters(function_type_t *type, declaration_t **last)
{
declaration_t *declarations = NULL;
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ',' || la1_type == ')') {
type->kr_style_parameters = true;
- declarations = parse_identifier_list();
+ declarations = parse_identifier_list(last);
goto parameters_finished;
}
}
expect(')');
restore_anchor_state(',', saved_comma_state);
+ *last = last_declaration;
return declarations;
end_error:
restore_anchor_state(',', saved_comma_state);
+ *last = NULL;
return NULL;
}
type = allocate_type_zero(TYPE_FUNCTION, HERE);
}
- declaration_t *parameters = parse_parameters(&type->function);
+ declaration_t *last;
+ declaration_t *parameters = parse_parameters(&type->function, &last);
if (declaration != NULL) {
- declaration->scope.declarations = parameters;
+ declaration->scope.declarations = parameters;
+ declaration->scope.last_declaration = last;
+ declaration->scope.is_parameter = true;
}
construct_function_type_t *construct_function_type =
declaration->is_inline = specifiers->is_inline;
declaration->storage_class = specifiers->declared_storage_class;
- if (declaration->storage_class == STORAGE_CLASS_NONE
- && scope != global_scope) {
+ if (declaration->storage_class == STORAGE_CLASS_NONE &&
+ scope != file_scope) {
declaration->storage_class = STORAGE_CLASS_AUTO;
}
if (warning.nested_externs &&
declaration->storage_class == STORAGE_CLASS_EXTERN &&
- scope != global_scope) {
+ scope != file_scope) {
warningf(&declaration->source_position,
"nested extern declaration of '%#T'", declaration->type, symbol);
}
assert(declaration != previous_declaration);
- if (previous_declaration != NULL
- && previous_declaration->parent_scope == scope) {
+ if (previous_declaration != NULL &&
+ previous_declaration->parent_scope->is_parameter &&
+ scope->depth == previous_declaration->parent_scope->depth + 1) {
+ errorf(&declaration->source_position,
+ "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+ orig_type, symbol, previous_declaration->type, symbol,
+ &previous_declaration->source_position);
+ goto finish;
+ }
+ if (previous_declaration != NULL &&
+ previous_declaration->parent_scope == scope) {
/* can happen for K&R style declarations */
if (previous_declaration->type == NULL) {
previous_declaration->type = declaration->type;
}
} else {
if (warning.missing_declarations &&
- scope == global_scope && (
+ scope == file_scope && (
declaration->storage_class == STORAGE_CLASS_NONE ||
declaration->storage_class == STORAGE_CLASS_THREAD
)) {
"no previous declaration for '%#T'", orig_type, symbol);
}
}
-
+finish:
assert(declaration->parent_scope == NULL);
assert(scope != NULL);
}
bool must_be_constant = false;
- if (declaration->storage_class == STORAGE_CLASS_STATIC
- || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
- || declaration->parent_scope == global_scope) {
+ if (declaration->storage_class == STORAGE_CLASS_STATIC ||
+ declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+ declaration->parent_scope == file_scope) {
must_be_constant = true;
}
add_anchor_token('{');
/* push function parameters */
- int top = environment_top();
- scope_t *last_scope = scope;
- set_scope(&declaration->scope);
+ size_t const top = environment_top();
+ scope_push(&declaration->scope);
declaration_t *parameter = declaration->scope.declarations;
for ( ; parameter != NULL; parameter = parameter->next) {
/* pop function parameters */
assert(scope == &declaration->scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
/* update function type */
type = skip_typeref(declaration->type);
/* push function parameters and switch scope */
- int top = environment_top();
- scope_t *last_scope = scope;
- set_scope(&declaration->scope);
+ size_t const top = environment_top();
+ scope_push(&declaration->scope);
declaration_t *parameter = declaration->scope.declarations;
for( ; parameter != NULL; parameter = parameter->next) {
}
assert(scope == &declaration->scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
}
eat('{');
add_anchor_token('}');
- while (token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}') {
+ if (token.type == T_EOF) {
+ errorf(HERE, "EOF while parsing struct");
+ break;
+ }
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
parse_compound_declarators(compound_declaration, &specifiers);
}
rem_anchor_token('}');
-
- if (token.type == T_EOF) {
- errorf(HERE, "EOF while parsing struct");
- }
next_token();
}
}
}
- type_t *type = declaration->type;
+ type_t *orig_type = declaration->type;
/* we always do the auto-type conversions; the & and sizeof parser contains
* code to revert this! */
- type = automatic_type_conversion(type);
+ type_t *type = automatic_type_conversion(orig_type);
ref->declaration = declaration;
ref->base.type = type;
/* this declaration is used */
declaration->used = true;
+ if (declaration->parent_scope != file_scope &&
+ declaration->parent_scope->depth < current_function->scope.depth &&
+ is_type_valid(orig_type) && !is_type_function(orig_type)) {
+ /* access of a variable from an outer function */
+ declaration->address_taken = true;
+ ref->is_outer_ref = true;
+ current_function->need_closure = true;
+ }
+
/* check for deprecated functions */
if (warning.deprecated_declarations &&
declaration->modifiers & DM_DEPRECATED) {
break;
default:
internal_errorf(HERE, "invalid compare builtin found");
- break;
}
expression->base.source_position = *HERE;
next_token();
candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
/* if we found a local label, we already created the declaration */
if (candidate != NULL) {
- assert(candidate->parent_scope == scope);
+ if (candidate->parent_scope != scope) {
+ assert(candidate->parent_scope->depth < scope->depth);
+ current_function->goto_to_outer = true;
+ }
return candidate;
}
PUSH_PARENT(statement);
- int top = environment_top();
- scope_t *last_scope = scope;
- set_scope(&statement->fors.scope);
+ size_t const top = environment_top();
+ scope_push(&statement->fors.scope);
expect('(');
add_anchor_token(')');
statement->fors.body = parse_loop_body(statement);
assert(scope == &statement->fors.scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
POP_PARENT;
POP_PARENT;
rem_anchor_token(')');
assert(scope == &statement->fors.scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
return create_invalid_statement();
statement = allocate_statement_zero(STATEMENT_GOTO);
statement->base.source_position = source_position;
statement->gotos.label = get_label(symbol);
+
+ if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) {
+ statement->gotos.outer_fkt_jmp = true;
+ }
}
/* remember the goto's in a list for later checking */
eat('{');
add_anchor_token('}');
- int top = environment_top();
- int top_local = local_label_top();
- scope_t *last_scope = scope;
- set_scope(&statement->compound.scope);
+ size_t const top = environment_top();
+ size_t const top_local = local_label_top();
+ scope_push(&statement->compound.scope);
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
- while (token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}') {
+ if (token.type == T_EOF) {
+ errorf(&statement->base.source_position,
+ "EOF while parsing compound statement");
+ break;
+ }
statement_t *sub_statement = intern_parse_statement();
if (is_invalid_statement(sub_statement)) {
/* an error occurred. if we are at an anchor, return */
anchor = &sub_statement->base.next;
}
-
- if (token.type == '}') {
- next_token();
- } else {
- errorf(&statement->base.source_position,
- "end of file while looking for closing '}'");
- }
+ next_token();
/* look over all statements again to produce no effect warnings */
if (warning.unused_value) {
end_error:
rem_anchor_token('}');
assert(scope == &statement->compound.scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
local_label_pop_to(top_local);
if (!warning.unused_function && !warning.unused_variable)
return;
- for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
+ for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) {
if (decl->used ||
decl->modifiers & DM_UNUSED ||
decl->modifiers & DM_USED ||
*/
static void parse_translation_unit(void)
{
+ add_anchor_token(T_EOF);
+
+#ifndef NDEBUG
+ unsigned char token_anchor_copy[T_LAST_TOKEN];
+ memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
+#endif
for (;;) {
#ifndef NDEBUG
bool anchor_leak = false;
for (int i = 0; i != T_LAST_TOKEN; ++i) {
- unsigned char count = token_anchor_set[i];
+ unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
errorf(HERE, "Leaked anchor token %k %d times", i, count);
anchor_leak = true;
break;
case T_EOF:
+ rem_anchor_token(T_EOF);
return;
case ';':
assert(unit == NULL);
unit = allocate_ast_zero(sizeof(unit[0]));
- assert(global_scope == NULL);
- global_scope = &unit->scope;
+ assert(file_scope == NULL);
+ file_scope = &unit->scope;
assert(scope == NULL);
- set_scope(&unit->scope);
+ scope_push(&unit->scope);
initialize_builtin_types();
}
translation_unit_t *finish_parsing(void)
{
+ /* do NOT use scope_pop() here, this will crash, will it by hand */
assert(scope == &unit->scope);
- scope = NULL;
+ scope = NULL;
last_declaration = NULL;
- assert(global_scope == &unit->scope);
+ assert(file_scope == &unit->scope);
check_unused_globals();
- global_scope = NULL;
+ file_scope = NULL;
DEL_ARR_F(environment_stack);
DEL_ARR_F(label_stack);