print_char(';');
}
+/**
+ * Print a computed goto statement.
+ *
+ * @param statement the computed goto statement
+ */
+static void print_computed_goto_statement(computed_goto_statement_t const *const stmt)
+{
+ print_string("goto *");
+ print_expression(stmt->expression);
+ print_char(';');
+}
+
/**
* Print a goto statement.
*
static void print_goto_statement(const goto_statement_t *statement)
{
print_string("goto ");
- if (statement->expression != NULL) {
- print_char('*');
- print_expression(statement->expression);
- } else {
- print_string(statement->label->base.symbol->string);
- }
+ print_string(statement->label->base.symbol->string);
print_char(';');
}
void print_statement(statement_t const *const stmt)
{
switch (stmt->kind) {
- case STATEMENT_ASM: print_asm_statement( &stmt->asms); break;
- case STATEMENT_BREAK: print_string("break;"); break;
- case STATEMENT_CASE_LABEL: print_case_label( &stmt->case_label); break;
- case STATEMENT_COMPOUND: print_compound_statement( &stmt->compound); break;
- case STATEMENT_CONTINUE: print_string("continue;"); break;
- case STATEMENT_DECLARATION: print_declaration_statement(&stmt->declaration); break;
- case STATEMENT_DO_WHILE: print_do_while_statement( &stmt->do_while); break;
- case STATEMENT_EMPTY: print_char(';'); break;
- case STATEMENT_ERROR: print_string("$error statement$"); break;
- case STATEMENT_EXPRESSION: print_expression_statement( &stmt->expression); break;
- case STATEMENT_FOR: print_for_statement( &stmt->fors); break;
- case STATEMENT_GOTO: print_goto_statement( &stmt->gotos); break;
- case STATEMENT_IF: print_if_statement( &stmt->ifs); break;
- case STATEMENT_LABEL: print_label_statement( &stmt->label); break;
- case STATEMENT_LEAVE: print_leave_statement( &stmt->leave); break;
- case STATEMENT_MS_TRY: print_ms_try_statement( &stmt->ms_try); break;
- case STATEMENT_RETURN: print_return_statement( &stmt->returns); break;
- case STATEMENT_SWITCH: print_switch_statement( &stmt->switchs); break;
- case STATEMENT_WHILE: print_while_statement( &stmt->whiles); break;
+ case STATEMENT_ASM: print_asm_statement( &stmt->asms); break;
+ case STATEMENT_BREAK: print_string("break;"); break;
+ case STATEMENT_CASE_LABEL: print_case_label( &stmt->case_label); break;
+ case STATEMENT_COMPOUND: print_compound_statement( &stmt->compound); break;
+ case STATEMENT_COMPUTED_GOTO: print_computed_goto_statement(&stmt->computed_goto); break;
+ case STATEMENT_CONTINUE: print_string("continue;"); break;
+ case STATEMENT_DECLARATION: print_declaration_statement( &stmt->declaration); break;
+ case STATEMENT_DO_WHILE: print_do_while_statement( &stmt->do_while); break;
+ case STATEMENT_EMPTY: print_char(';'); break;
+ case STATEMENT_ERROR: print_string("$error statement$"); break;
+ case STATEMENT_EXPRESSION: print_expression_statement( &stmt->expression); break;
+ case STATEMENT_FOR: print_for_statement( &stmt->fors); break;
+ case STATEMENT_GOTO: print_goto_statement( &stmt->gotos); break;
+ case STATEMENT_IF: print_if_statement( &stmt->ifs); break;
+ case STATEMENT_LABEL: print_label_statement( &stmt->label); break;
+ case STATEMENT_LEAVE: print_leave_statement( &stmt->leave); break;
+ case STATEMENT_MS_TRY: print_ms_try_statement( &stmt->ms_try); break;
+ case STATEMENT_RETURN: print_return_statement( &stmt->returns); break;
+ case STATEMENT_SWITCH: print_switch_statement( &stmt->switchs); break;
+ case STATEMENT_WHILE: print_while_statement( &stmt->whiles); break;
}
}
typedef struct switch_statement_t switch_statement_t;
typedef struct declaration_statement_t declaration_statement_t;
typedef struct expression_statement_t expression_statement_t;
+typedef struct computed_goto_statement_t computed_goto_statement_t;
typedef struct goto_statement_t goto_statement_t;
typedef struct label_statement_t label_statement_t;
typedef struct case_label_statement_t case_label_statement_t;
statement_to_firm(statement->statement);
}
+static void computed_goto_to_firm(computed_goto_statement_t const *const statement)
+{
+ if (!currently_reachable())
+ return;
+
+ ir_node *const irn = expression_to_firm(statement->expression);
+ dbg_info *const dbgi = get_dbg_info(&statement->base.source_position);
+ ir_node *const ijmp = new_d_IJmp(dbgi, irn);
+
+ set_irn_link(ijmp, ijmp_list);
+ ijmp_list = ijmp;
+
+ set_unreachable_now();
+}
+
static void goto_to_firm(const goto_statement_t *statement)
{
if (!currently_reachable())
return;
- if (statement->expression) {
- ir_node *irn = expression_to_firm(statement->expression);
- dbg_info *dbgi = get_dbg_info(&statement->base.source_position);
- ir_node *ijmp = new_d_IJmp(dbgi, irn);
+ ir_node *block = get_label_block(statement->label);
+ ir_node *jmp = new_Jmp();
+ add_immBlock_pred(block, jmp);
- set_irn_link(ijmp, ijmp_list);
- ijmp_list = ijmp;
- } else {
- ir_node *block = get_label_block(statement->label);
- ir_node *jmp = new_Jmp();
- add_immBlock_pred(block, jmp);
- }
set_unreachable_now();
}
case STATEMENT_LABEL:
label_to_firm(&statement->label);
return;
+ case STATEMENT_COMPUTED_GOTO:
+ computed_goto_to_firm(&statement->computed_goto);
+ return;
case STATEMENT_GOTO:
goto_to_firm(&statement->gotos);
return;
STATEMENT_EXPRESSION,
STATEMENT_CONTINUE,
STATEMENT_BREAK,
+ STATEMENT_COMPUTED_GOTO,
STATEMENT_GOTO,
STATEMENT_LABEL,
STATEMENT_CASE_LABEL,
struct goto_statement_t {
statement_base_t base;
label_t *label; /**< The destination label. */
- expression_t *expression; /**< The expression for an assigned goto. */
goto_statement_t *next; /**< links all goto statements of a function */
};
+struct computed_goto_statement_t {
+ statement_base_t base;
+ expression_t *expression; /**< The expression for the computed goto. */
+};
+
struct case_label_statement_t {
statement_base_t base;
expression_t *expression; /**< The case label expression, NULL for default label. */
};
union statement_t {
- statement_kind_t kind;
- statement_base_t base;
- return_statement_t returns;
- compound_statement_t compound;
- declaration_statement_t declaration;
- if_statement_t ifs;
- switch_statement_t switchs;
- goto_statement_t gotos;
- case_label_statement_t case_label;
- label_statement_t label;
- expression_statement_t expression;
- while_statement_t whiles;
- do_while_statement_t do_while;
- for_statement_t fors;
- asm_statement_t asms;
- ms_try_statement_t ms_try;
- leave_statement_t leave;
+ statement_kind_t kind;
+ statement_base_t base;
+ return_statement_t returns;
+ compound_statement_t compound;
+ declaration_statement_t declaration;
+ if_statement_t ifs;
+ switch_statement_t switchs;
+ computed_goto_statement_t computed_goto;
+ goto_statement_t gotos;
+ case_label_statement_t case_label;
+ label_statement_t label;
+ expression_statement_t expression;
+ while_statement_t whiles;
+ do_while_statement_t do_while;
+ for_statement_t fors;
+ asm_statement_t asms;
+ ms_try_statement_t ms_try;
+ leave_statement_t leave;
};
struct translation_unit_t {
static size_t get_statement_struct_size(statement_kind_t kind)
{
static const size_t sizes[] = {
- [STATEMENT_ERROR] = sizeof(statement_base_t),
- [STATEMENT_EMPTY] = sizeof(statement_base_t),
- [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
- [STATEMENT_RETURN] = sizeof(return_statement_t),
- [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
- [STATEMENT_IF] = sizeof(if_statement_t),
- [STATEMENT_SWITCH] = sizeof(switch_statement_t),
- [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
- [STATEMENT_CONTINUE] = sizeof(statement_base_t),
- [STATEMENT_BREAK] = sizeof(statement_base_t),
- [STATEMENT_GOTO] = sizeof(goto_statement_t),
- [STATEMENT_LABEL] = sizeof(label_statement_t),
- [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
- [STATEMENT_WHILE] = sizeof(while_statement_t),
- [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
- [STATEMENT_FOR] = sizeof(for_statement_t),
- [STATEMENT_ASM] = sizeof(asm_statement_t),
- [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
- [STATEMENT_LEAVE] = sizeof(leave_statement_t)
+ [STATEMENT_ERROR] = sizeof(statement_base_t),
+ [STATEMENT_EMPTY] = sizeof(statement_base_t),
+ [STATEMENT_COMPOUND] = sizeof(compound_statement_t),
+ [STATEMENT_RETURN] = sizeof(return_statement_t),
+ [STATEMENT_DECLARATION] = sizeof(declaration_statement_t),
+ [STATEMENT_IF] = sizeof(if_statement_t),
+ [STATEMENT_SWITCH] = sizeof(switch_statement_t),
+ [STATEMENT_EXPRESSION] = sizeof(expression_statement_t),
+ [STATEMENT_CONTINUE] = sizeof(statement_base_t),
+ [STATEMENT_BREAK] = sizeof(statement_base_t),
+ [STATEMENT_COMPUTED_GOTO] = sizeof(computed_goto_statement_t),
+ [STATEMENT_GOTO] = sizeof(goto_statement_t),
+ [STATEMENT_LABEL] = sizeof(label_statement_t),
+ [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t),
+ [STATEMENT_WHILE] = sizeof(while_statement_t),
+ [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t),
+ [STATEMENT_FOR] = sizeof(for_statement_t),
+ [STATEMENT_ASM] = sizeof(asm_statement_t),
+ [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t),
+ [STATEMENT_LEAVE] = sizeof(leave_statement_t)
};
assert((size_t)kind < lengthof(sizes));
assert(sizes[kind] != 0);
for (const goto_statement_t *goto_statement = goto_first;
goto_statement != NULL;
goto_statement = goto_statement->next) {
- /* skip computed gotos */
- if (goto_statement->expression != NULL)
- continue;
-
label_t *label = goto_statement->label;
if (label->base.source_position.input_name == NULL) {
print_in_function();
found_break_parent:
break;
- case STATEMENT_GOTO:
- if (stmt->gotos.expression) {
- if (!expression_returns(stmt->gotos.expression))
- return;
+ case STATEMENT_COMPUTED_GOTO: {
+ if (!expression_returns(stmt->computed_goto.expression))
+ return;
- statement_t *parent = stmt->base.parent;
- if (parent == NULL) /* top level goto */
- return;
- next = parent;
- } else {
- next = stmt->gotos.label->statement;
- if (next == NULL) /* missing label */
- return;
- }
+ statement_t *parent = stmt->base.parent;
+ if (parent == NULL) /* top level goto */
+ return;
+ next = parent;
+ break;
+ }
+
+ case STATEMENT_GOTO:
+ next = stmt->gotos.label->statement;
+ if (next == NULL) /* missing label */
+ return;
break;
case STATEMENT_LABEL:
case STATEMENT_RETURN:
case STATEMENT_CONTINUE:
case STATEMENT_BREAK:
+ case STATEMENT_COMPUTED_GOTO:
case STATEMENT_GOTO:
case STATEMENT_LEAVE:
panic("invalid control flow in function");
*/
static statement_t *parse_goto(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
- eat(T_goto);
+ statement_t *statement;
+ if (GNU_MODE && look_ahead(1)->kind == '*') {
+ statement = allocate_statement_zero(STATEMENT_COMPUTED_GOTO);
+ eat(T_goto);
+ eat('*');
- if (GNU_MODE && next_if('*')) {
expression_t *expression = parse_expression();
mark_vars_read(expression, NULL);
expression = create_implicit_cast(expression, type_void_ptr);
}
- statement->gotos.expression = expression;
- } else if (token.kind == T_IDENTIFIER) {
- label_t *const label = get_label();
- label->used = true;
- statement->gotos.label = label;
+ statement->computed_goto.expression = expression;
} else {
- if (GNU_MODE)
- parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
- else
- parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_until_anchor();
- return create_error_statement();
+ statement = allocate_statement_zero(STATEMENT_GOTO);
+ eat(T_goto);
+ if (token.kind == T_IDENTIFIER) {
+ label_t *const label = get_label();
+ label->used = true;
+ statement->gotos.label = label;
+
+ /* remember the goto's in a list for later checking */
+ *goto_anchor = &statement->gotos;
+ goto_anchor = &statement->gotos.next;
+ } else {
+ if (GNU_MODE)
+ parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+ else
+ parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+ eat_until_anchor();
+ return create_error_statement();
+ }
}
- /* remember the goto's in a list for later checking */
- *goto_anchor = &statement->gotos;
- goto_anchor = &statement->gotos.next;
-
expect(';', end_error);
end_error:
walk_statement(stmt->ms_try.final_statement, env);
return;
- case STATEMENT_GOTO:
- if (stmt->gotos.expression)
- walk_expression(stmt->gotos.expression, env);
+ case STATEMENT_COMPUTED_GOTO:
+ walk_expression(stmt->computed_goto.expression, env);
return;
case STATEMENT_ERROR:
case STATEMENT_CONTINUE:
case STATEMENT_BREAK:
case STATEMENT_ASM:
+ case STATEMENT_GOTO:
case STATEMENT_LEAVE:
return;
}