const declaration_statement_t *statement)
{
bool first = true;
- for (declaration_t *declaration = statement->declarations_begin;
- declaration != statement->declarations_end->next;
- declaration = declaration->next) {
- if (declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
- continue;
- if (declaration->implicit)
- continue;
-
- if (!first) {
- print_indent();
- } else {
- first = false;
+ declaration_t *declaration = statement->declarations_begin;
+
+ if (declaration->namespc == NAMESPACE_LOCAL_LABEL) {
+ fputs("__label__ ", out);
+ for (;
+ declaration != statement->declarations_end->next;
+ declaration = declaration->next) {
+ if (!first) {
+ fputs(", ", out);
+ } else {
+ first = false;
+ }
+ fputs(declaration->symbol->string, out);
+ }
+ fputs(";\n", out);
+ } else {
+ for (;
+ declaration != statement->declarations_end->next;
+ declaration = declaration->next) {
+ if (declaration->storage_class == STORAGE_CLASS_ENUM_ENTRY)
+ continue;
+ if (declaration->implicit)
+ continue;
+
+ if (!first) {
+ print_indent();
+ } else {
+ first = false;
+ }
+ print_declaration(declaration);
+ fputc('\n', out);
}
- print_declaration(declaration);
- fputc('\n', out);
}
}
*/
void print_declaration(const declaration_t *declaration)
{
- if(declaration->namespc != NAMESPACE_NORMAL &&
- declaration->symbol == NULL)
+ if (declaration->namespc != NAMESPACE_NORMAL &&
+ declaration->symbol == NULL)
return;
- switch(declaration->namespc) {
+ switch (declaration->namespc) {
case NAMESPACE_NORMAL:
print_normal_declaration(declaration);
break;
static int lookahead_bufpos;
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;
static scope_t *scope = NULL;
static declaration_t *last_declaration = NULL;
}
/**
- * Returns the index of the top element of the label stack.
+ * Returns the index of the top element of the global label stack.
*/
static size_t label_top(void)
{
return ARR_LEN(label_stack);
}
+/**
+ * Returns the index of the top element of the local label stack.
+ */
+static size_t local_label_top(void)
+{
+ return ARR_LEN(local_label_stack);
+}
+
/**
* Return the next token.
*/
ARR_APP1(stack_entry_t, *stack_ptr, entry);
}
+/**
+ * Push a declaration on the environment stack.
+ *
+ * @param declaration the declaration
+ */
static void environment_push(declaration_t *declaration)
{
assert(declaration->source_position.input_name != NULL);
}
/**
- * Push a declaration of the label stack.
+ * Push a declaration on the global label stack.
*
* @param declaration the declaration
*/
stack_push(&label_stack, declaration);
}
+/**
+ * Push a declaration of the local label stack.
+ *
+ * @param declaration the declaration
+ */
+static void local_label_push(declaration_t *declaration)
+{
+ assert(declaration->parent_scope != NULL);
+ stack_push(&local_label_stack, declaration);
+}
+
/**
* pops symbols from the environment stack until @p new_top is the top element
*/
ARR_SHRINKLEN(*stack_ptr, (int) new_top);
}
+/**
+ * Pop all entries from the environment stack until the new_top
+ * is reached.
+ *
+ * @param new_top the new stack top
+ */
static void environment_pop_to(size_t new_top)
{
stack_pop_to(&environment_stack, new_top);
}
/**
- * Pop all entries on the label stack until the new_top
+ * Pop all entries from the global label stack until the new_top
* is reached.
*
* @param new_top the new stack top
stack_pop_to(&label_stack, new_top);
}
+/**
+ * Pop all entries from the local label stack until the new_top
+ * is reached.
+ *
+ * @param new_top the new stack top
+ */
+static void local_label_pop_to(size_t new_top)
+{
+ stack_pop_to(&local_label_stack, new_top);
+}
+
+
static int get_akind_rank(atomic_type_kind_t akind)
{
return (int) akind;
*/
static declaration_t *get_label(symbol_t *symbol)
{
- declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL);
+ declaration_t *candidate;
assert(current_function != NULL);
+
+ 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);
+ return candidate;
+ }
+
+ candidate = get_declaration(symbol, NAMESPACE_LABEL);
/* if we found a label in the same function, then we already created the
* declaration */
if (candidate != NULL
PUSH_PARENT(statement);
- /* if source position is already set then the label is defined twice,
- * otherwise it was just mentioned in a goto so far */
- if (label->source_position.input_name != NULL) {
+ /* if statement is already set then the label is defined twice,
+ * otherwise it was just mentioned in a goto/local label declaration so far */
+ if (label->init.statement != NULL) {
errorf(HERE, "duplicate label '%Y' (declared %P)",
symbol, &label->source_position);
} else {
/**
* Parse a __leave statement.
*/
-static statement_t *parse_leave(void)
+static statement_t *parse_leave_statement(void)
{
if (current_try == NULL) {
errorf(HERE, "__leave statement not within __try");
return statement;
}
+static statement_t *parse_local_label_declaration(void) {
+ statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
+ statement->base.source_position = token.source_position;
+
+ eat(T___label__);
+
+ declaration_t *begin = NULL, *end = NULL;
+
+ while (true) {
+ if (token.type != T_IDENTIFIER) {
+ parse_error_expected("while parsing local label declaration",
+ T_IDENTIFIER, NULL);
+ goto end_error;
+ }
+ symbol_t *symbol = token.v.symbol;
+ declaration_t *declaration = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
+ if (declaration != NULL) {
+ errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition at %P)",
+ symbol, &declaration->source_position);
+ } else {
+ declaration = allocate_declaration_zero();
+ declaration->namespc = NAMESPACE_LOCAL_LABEL;
+ declaration->source_position = token.source_position;
+ declaration->symbol = symbol;
+ declaration->parent_scope = scope;
+ declaration->init.statement = NULL;
+
+ if (end != NULL)
+ end->next = declaration;
+ end = declaration;
+ if (begin == NULL)
+ begin = declaration;
+
+ local_label_push(declaration);
+ }
+ next_token();
+
+ if (token.type != ',')
+ break;
+ next_token();
+ }
+ eat(';');
+end_error:
+ statement->declaration.declarations_begin = begin;
+ statement->declaration.declarations_end = end;
+ return statement;
+}
+
/**
* Parse a statement.
* There's also parse_statement() which additionally checks for
statement = parse_declaration_statement();
break;
+ case T___label__:
+ statement = parse_local_label_declaration();
+ break;
+
case ';': statement = parse_empty_statement(); break;
case '{': statement = parse_compound_statement(false); break;
- case T___leave: statement = parse_leave(); break;
+ case T___leave: statement = parse_leave_statement(); break;
case T___try: statement = parse_ms_try_statment(); break;
case T_asm: statement = parse_asm_statement(); break;
case T_break: statement = parse_break(); break;
add_anchor_token('}');
int top = environment_top();
+ int top_local = local_label_top();
scope_t *last_scope = scope;
set_scope(&statement->compound.scope);
assert(scope == &statement->compound.scope);
set_scope(last_scope);
environment_pop_to(top);
+ local_label_pop_to(top_local);
POP_PARENT;
return statement;
{
environment_stack = NEW_ARR_F(stack_entry_t, 0);
label_stack = NEW_ARR_F(stack_entry_t, 0);
+ local_label_stack = NEW_ARR_F(stack_entry_t, 0);
diagnostic_count = 0;
error_count = 0;
warning_count = 0;
DEL_ARR_F(environment_stack);
DEL_ARR_F(label_stack);
+ DEL_ARR_F(local_label_stack);
translation_unit_t *result = unit;
unit = NULL;
void parse(void)
{
lookahead_bufpos = 0;
- for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
+ for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
next_token();
}
parse_translation_unit();