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;
parse_error_expected(NULL, (expected), NULL); \
add_anchor_token(expected); \
eat_until_anchor(); \
- next_if((expected)); \
rem_anchor_token(expected); \
- goto error_label; \
+ if (token.type != (expected)) \
+ goto error_label; \
} \
next_token(); \
} while (0)
expression_t *expression = NULL;
- bool old_type_prop = in_type_prop;
- bool old_gcc_extension = in_gcc_extension;
- in_type_prop = true;
+ bool old_type_prop = in_type_prop;
+ in_type_prop = true;
- while (next_if(T___extension__)) {
- /* This can be a prefix to a typename or an expression. */
- in_gcc_extension = true;
- }
switch (token.type) {
case T_IDENTIFIER:
if (is_typedef_symbol(token.symbol)) {
}
break;
}
- in_type_prop = old_type_prop;
- in_gcc_extension = old_gcc_extension;
+ in_type_prop = old_type_prop;
rem_anchor_token(')');
expect(')', end_error);
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
- type_t *type = NULL;
- type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
- unsigned type_specifiers = 0;
- bool newtype = false;
- bool saw_error = false;
- bool old_gcc_extension = in_gcc_extension;
+ type_t *type = NULL;
+ type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
+ unsigned type_specifiers = 0;
+ bool newtype = false;
+ bool saw_error = false;
memset(specifiers, 0, sizeof(*specifiers));
specifiers->source_position = token.source_position;
MATCH_TYPE_QUALIFIER(T___uptr, TYPE_QUALIFIER_UPTR);
MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR);
- case T___extension__:
- next_token();
- in_gcc_extension = true;
- break;
-
/* type specifiers */
#define MATCH_SPECIFIER(token, specifier, name) \
case token: \
finish_specifiers:
specifiers->attributes = parse_attributes(specifiers->attributes);
- in_gcc_extension = old_gcc_extension;
-
if (type == NULL || (saw_error && type_specifiers != 0)) {
atomic_type_kind_t atomic_type;
goto parameters_finished;
case T_IDENTIFIER:
- case T___extension__:
DECLARATION_START
{
entity_t *entity = parse_parameter();
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) {
for (;;) {
switch (token.type) {
DECLARATION_START
- case T___extension__:
/* This covers symbols, which are no type, too, and results in
* better error messages. The typical cases are misspelled type
* names and missing includes. */
}
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,
eat('{');
add_anchor_token('}');
- while (token.type != '}') {
- if (token.type == T_EOF) {
- errorf(HERE, "EOF while parsing struct");
- break;
+ for (;;) {
+ switch (token.type) {
+ DECLARATION_START
+ case T___extension__:
+ case T_IDENTIFIER: {
+ PUSH_EXTENSION();
+ declaration_specifiers_t specifiers;
+ parse_declaration_specifiers(&specifiers);
+ parse_compound_declarators(compound, &specifiers);
+ POP_EXTENSION();
+ break;
+ }
+
+ default:
+ rem_anchor_token('}');
+ expect('}', end_error);
+end_error:
+ /* §6.7.2.1:7 */
+ compound->complete = true;
+ return;
}
- declaration_specifiers_t specifiers;
- parse_declaration_specifiers(&specifiers);
- parse_compound_declarators(compound, &specifiers);
}
- rem_anchor_token('}');
- next_token();
-
- /* §6.7.2.1:7 */
- compound->complete = true;
}
static type_t *parse_typename(void)
static expression_t *parse_boolean_literal(bool value)
{
expression_t *literal = allocate_expression_zero(EXPR_LITERAL_BOOLEAN);
- literal->base.source_position = token.source_position;
- literal->base.type = type_bool;
- literal->literal.value.begin = value ? "true" : "false";
- literal->literal.value.size = value ? 4 : 5;
+ literal->base.type = type_bool;
+ literal->literal.value.begin = value ? "true" : "false";
+ literal->literal.value.size = value ? 4 : 5;
next_token();
return literal;
}
expression_t *literal = allocate_expression_zero(kind);
- literal->base.source_position = token.source_position;
- literal->base.type = type;
- literal->literal.value = token.literal;
- literal->literal.suffix = token.symbol;
+ literal->base.type = type;
+ literal->literal.value = token.literal;
+ literal->literal.suffix = token.symbol;
next_token();
/* integer type depends on the size of the number and the size
static expression_t *parse_character_constant(void)
{
expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER);
- literal->base.source_position = token.source_position;
- literal->base.type = c_mode & _CXX ? type_char : type_int;
- literal->literal.value = token.literal;
+ literal->base.type = c_mode & _CXX ? type_char : type_int;
+ literal->literal.value = token.literal;
size_t len = literal->literal.value.size;
if (len > 1) {
static expression_t *parse_wide_character_constant(void)
{
expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER);
- literal->base.source_position = token.source_position;
- literal->base.type = type_int;
- literal->literal.value = token.literal;
+ literal->base.type = type_int;
+ literal->literal.value = token.literal;
size_t len = wstrlen(&literal->literal.value);
if (len > 1) {
return true;
}
-static expression_t *parse_compound_literal(type_t *type)
+static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type)
{
expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
+ expression->base.source_position = *pos;
parse_initializer_env_t env;
env.type = type;
*/
static expression_t *parse_cast(void)
{
- source_position_t source_position = token.source_position;
+ source_position_t const pos = *HERE;
eat('(');
add_anchor_token(')');
expect(')', end_error);
if (token.type == '{') {
- return parse_compound_literal(type);
+ return parse_compound_literal(&pos, type);
}
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
- cast->base.source_position = source_position;
+ cast->base.source_position = pos;
expression_t *value = parse_subexpression(PREC_CAST);
cast->base.type = type;
{
/* the result is a (int)0 */
expression_t *literal = allocate_expression_zero(EXPR_LITERAL_MS_NOOP);
- literal->base.type = type_int;
- literal->base.source_position = token.source_position;
- literal->literal.value.begin = "__noop";
- literal->literal.value.size = 6;
+ literal->base.type = type_int;
+ literal->literal.value.begin = "__noop";
+ literal->literal.value.size = 6;
eat(T___noop);
type_t *orig_type;
expression_t *expression;
if (token.type == '(' && is_declaration_specifier(look_ahead(1))) {
+ source_position_t const pos = *HERE;
next_token();
add_anchor_token(')');
orig_type = parse_typename();
if (token.type == '{') {
/* It was not sizeof(type) after all. It is sizeof of an expression
* starting with a compound literal */
- expression = parse_compound_literal(orig_type);
+ expression = parse_compound_literal(&pos, orig_type);
goto typeprop_expression;
}
} else {
*/
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);
}
statement->case_label.statement = parse_label_inner_statement(statement, "case label");
- POP_PARENT;
+ POP_PARENT();
return statement;
}
statement->case_label.statement = parse_label_inner_statement(statement, "default label");
- POP_PARENT;
+ POP_PARENT();
return statement;
}
*label_anchor = &statement->label;
label_anchor = &statement->label.next;
- POP_PARENT;
+ POP_PARENT();
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;
warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
}
- POP_PARENT;
+ POP_PARENT();
return statement;
}
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) {
}
check_enum_cases(&statement->switchs);
- POP_PARENT;
+ POP_PARENT();
return statement;
end_error:
- POP_PARENT;
+ POP_PARENT();
return create_invalid_statement();
}
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;
statement->whiles.body = parse_loop_body(statement);
- POP_PARENT;
+ POP_PARENT();
return statement;
end_error:
- POP_PARENT;
+ POP_PARENT();
return create_invalid_statement();
}
expect(')', end_error);
expect(';', end_error);
- POP_PARENT;
+ POP_PARENT();
return statement;
end_error:
- POP_PARENT;
+ POP_PARENT();
return create_invalid_statement();
}
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_PARENT;
+ POP_SCOPE();
+ POP_PARENT();
return statement;
end_error2:
- POP_PARENT;
+ POP_PARENT();
rem_anchor_token(')');
- assert(current_scope == &statement->fors.scope);
- scope_pop(old_scope);
- environment_pop_to(top);
+ POP_SCOPE();
/* fallthrough */
end_error1:
statement->ms_try.try_statement = parse_compound_statement(false);
current_try = rem;
- POP_PARENT;
+ POP_PARENT();
if (next_if(T___except)) {
expect('(', end_error);
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_PARENT;
+ 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;