static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
-#define PUSH_PARENT(stmt) \
- statement_t *const prev_parent = current_parent; \
- ((void)(current_parent = (stmt)))
-#define POP_PARENT() ((void)(current_parent = prev_parent))
+#define PUSH_PARENT(stmt) \
+ statement_t *const new_parent = (stmt); \
+ statement_t *const old_parent = current_parent; \
+ ((void)(current_parent = new_parent))
+#define POP_PARENT() (assert(current_parent == new_parent), (void)(current_parent = old_parent))
+
+#define PUSH_SCOPE(scope) \
+ size_t const top = environment_top(); \
+ scope_t *const new_scope = (scope); \
+ scope_t *const old_scope = scope_push(new_scope)
+#define POP_SCOPE() (assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top))
+
+#define PUSH_EXTENSION() \
+ bool const old_gcc_extension = in_gcc_extension; \
+ while (next_if(T___extension__)) { \
+ in_gcc_extension = true; \
+ } \
+ do {} while (0)
+#define POP_EXTENSION() \
+ ((void)(in_gcc_extension = old_gcc_extension))
/** special symbol used for anonymous entities. */
static symbol_t *sym_anonymous = NULL;
add_anchor_token('{');
- /* push function parameters */
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&entity->function.parameters);
+ PUSH_SCOPE(&entity->function.parameters);
entity_t *parameter = entity->function.parameters.entities;
for ( ; parameter != NULL; parameter = parameter->base.next) {
}
decl_list_end:
- /* pop function parameters */
- assert(current_scope == &entity->function.parameters);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
/* update function type */
type_t *new_type = duplicate_type(type);
assert(is_declaration(entity));
type = skip_typeref(entity->declaration.type);
- /* push function parameters and switch scope */
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&function->parameters);
+ PUSH_SCOPE(&function->parameters);
entity_t *parameter = function->parameters.entities;
for (; parameter != NULL; parameter = parameter->base.next) {
entity_t *old_current_entity = current_entity;
current_function = function;
current_entity = entity;
- current_parent = NULL;
+ PUSH_PARENT(NULL);
goto_first = NULL;
goto_anchor = &goto_first;
}
}
- assert(current_parent == NULL);
+ POP_PARENT();
assert(current_function == function);
assert(current_entity == entity);
current_entity = old_current_entity;
label_pop_to(label_stack_top);
}
- assert(current_scope == &function->parameters);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
}
static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
*/
static expression_t *parse_extension(void)
{
- eat(T___extension__);
-
- bool old_gcc_extension = in_gcc_extension;
- in_gcc_extension = true;
+ PUSH_EXTENSION();
expression_t *expression = parse_subexpression(PREC_UNARY);
- in_gcc_extension = old_gcc_extension;
+ POP_EXTENSION();
return expression;
}
default:
inner_stmt = parse_statement();
- /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
}
return statement;
}
+static statement_t *parse_inner_statement(void)
+{
+ statement_t *const stmt = parse_statement();
+ /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */
+ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */
+ if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+ errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+ }
+ return stmt;
+}
+
/**
* Parse an if statement.
*/
rem_anchor_token('{');
add_anchor_token(T_else);
- statement_t *const true_stmt = parse_statement();
+ statement_t *const true_stmt = parse_inner_statement();
statement->ifs.true_statement = true_stmt;
rem_anchor_token(T_else);
if (next_if(T_else)) {
- statement->ifs.false_statement = parse_statement();
+ statement->ifs.false_statement = parse_inner_statement();
} else if (true_stmt->kind == STATEMENT_IF &&
true_stmt->ifs.false_statement != NULL) {
source_position_t const *const pos = &true_stmt->base.source_position;
switch_statement_t *rem = current_switch;
current_switch = &statement->switchs;
- statement->switchs.body = parse_statement();
+ statement->switchs.body = parse_inner_statement();
current_switch = rem;
if (statement->switchs.default_label == NULL) {
statement_t *const rem = current_loop;
current_loop = loop;
- statement_t *const body = parse_statement();
+ statement_t *const body = parse_inner_statement();
current_loop = rem;
return body;
add_anchor_token(')');
PUSH_PARENT(statement);
+ PUSH_SCOPE(&statement->fors.scope);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&statement->fors.scope);
-
- bool old_gcc_extension = in_gcc_extension;
- while (next_if(T___extension__)) {
- in_gcc_extension = true;
- }
+ PUSH_EXTENSION();
if (next_if(';')) {
} else if (is_declaration_specifier(&token)) {
rem_anchor_token(';');
expect(';', end_error2);
}
- in_gcc_extension = old_gcc_extension;
+
+ POP_EXTENSION();
if (token.type != ';') {
add_anchor_token(';');
rem_anchor_token(')');
statement->fors.body = parse_loop_body(statement);
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
-
+ POP_SCOPE();
POP_PARENT();
return statement;
end_error2:
POP_PARENT();
rem_anchor_token(')');
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
/* fallthrough */
end_error1:
environment_push(entity);
append_entity(current_scope, entity);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&entity->namespacee.members);
+ PUSH_SCOPE(&entity->namespacee.members);
entity_t *old_current_entity = current_entity;
current_entity = entity;
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);
+ POP_SCOPE();
}
/**
break;
}
- case T___extension__:
+ 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. */
- while (next_if(T___extension__)) {}
- bool old_gcc_extension = in_gcc_extension;
- in_gcc_extension = true;
+ PUSH_EXTENSION();
statement = intern_parse_statement();
- in_gcc_extension = old_gcc_extension;
+ POP_EXTENSION();
break;
+ }
DECLARATION_START
statement = parse_declaration_statement();
statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
PUSH_PARENT(statement);
+ PUSH_SCOPE(&statement->compound.scope);
eat('{');
add_anchor_token('}');
add_anchor_token(T_wchar_t);
add_anchor_token(T_while);
- size_t const top = environment_top();
- scope_t *old_scope = scope_push(&statement->compound.scope);
-
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
while (token.type != '}') {
rem_anchor_token('&');
rem_anchor_token('!');
rem_anchor_token('}');
- assert(current_scope == &statement->compound.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
POP_PARENT();
return statement;
}
static void parse_external(void)
{
switch (token.type) {
- DECLARATION_START_NO_EXTERN
- case T_IDENTIFIER:
- case T___extension__:
- /* tokens below are for implicit int */
- case '&': /* & x; -> int& x; (and error later, because C++ has no
- implicit int) */
- case '*': /* * x; -> int* x; */
- case '(': /* (x); -> int (x); */
- parse_external_declaration();
- return;
-
case T_extern:
if (look_ahead(1)->type == T_STRING_LITERAL) {
parse_linkage_specification();
} else {
+ DECLARATION_START_NO_EXTERN
+ case T_IDENTIFIER:
+ case T___extension__:
+ /* tokens below are for implicit int */
+ case '&': /* & x; -> int& x; (and error later, because C++ has no
+ implicit int) */
+ case '*': /* * x; -> int* x; */
+ case '(':; /* (x); -> int (x); */
+ PUSH_EXTENSION();
parse_external_declaration();
+ POP_EXTENSION();
}
return;