authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-26 15:58:49-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-26 15:58:49-05:00
logaa2ca3f02c11c133964d793847c925e3bd131b27
treeff4c1249197827143be19b9d369f16330e930c23
parent1b0e90f70b4dc26c2ba96b7b5709a3ff269bb48a

translate-c: better way to translate switch

previously `continue` would be handled incorrectly

2 files changed, 42 insertions(+), 25 deletions(-)

src/translate_c.cpp+38-22
...@@ -82,6 +82,7 @@ struct TransScopeSwitch {...@@ -82,6 +82,7 @@ struct TransScopeSwitch {
82 AstNode *switch_node;82 AstNode *switch_node;
83 uint32_t case_index;83 uint32_t case_index;
84 bool found_default;84 bool found_default;
85 Buf *end_label_name;
85};86};
8687
87struct TransScopeVar {88struct TransScopeVar {
...@@ -248,6 +249,18 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol...@@ -248,6 +249,18 @@ static AstNode *trans_create_node_addr_of(Context *c, bool is_const, bool is_vol
248 return node;249 return node;
249}250}
250251
252static AstNode *trans_create_node_goto(Context *c, Buf *label_name) {
253 AstNode *goto_node = trans_create_node(c, NodeTypeGoto);
254 goto_node->data.goto_expr.name = label_name;
255 return goto_node;
256}
257
258static AstNode *trans_create_node_label(Context *c, Buf *label_name) {
259 AstNode *label_node = trans_create_node(c, NodeTypeLabel);
260 label_node->data.label.name = label_name;
261 return label_node;
262}
263
251static AstNode *trans_create_node_bool(Context *c, bool value) {264static AstNode *trans_create_node_bool(Context *c, bool value) {
252 AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral);265 AstNode *bool_node = trans_create_node(c, NodeTypeBoolLiteral);
253 bool_node->data.bool_literal.value = value;266 bool_node->data.bool_literal.value = value;
...@@ -2283,11 +2296,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt...@@ -2283,11 +2296,7 @@ static AstNode *trans_do_loop(Context *c, TransScope *parent_scope, const DoStmt
2283}2296}
22842297
2285static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {2298static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const SwitchStmt *stmt) {
2286 TransScopeWhile *while_scope = trans_scope_while_create(c, parent_scope);2299 TransScopeBlock *block_scope = trans_scope_block_create(c, parent_scope);
2287 while_scope->node->data.while_expr.condition = trans_create_node_bool(c, true);
2288
2289 TransScopeBlock *block_scope = trans_scope_block_create(c, &while_scope->base);
2290 while_scope->node->data.while_expr.body = block_scope->node;
22912300
2292 TransScopeSwitch *switch_scope;2301 TransScopeSwitch *switch_scope;
22932302
...@@ -2305,6 +2314,10 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw...@@ -2305,6 +2314,10 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw
2305 }2314 }
2306 block_scope->node->data.block.statements.append(switch_scope->switch_node);2315 block_scope->node->data.block.statements.append(switch_scope->switch_node);
23072316
2317 // TODO avoid name collisions
2318 Buf *end_label_name = buf_create_from_str("end");
2319 switch_scope->end_label_name = end_label_name;
2320
2308 const Expr *cond_expr = stmt->getCond();2321 const Expr *cond_expr = stmt->getCond();
2309 assert(cond_expr != nullptr);2322 assert(cond_expr != nullptr);
23102323
...@@ -2336,9 +2349,11 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw...@@ -2336,9 +2349,11 @@ static AstNode *trans_switch_stmt(Context *c, TransScope *parent_scope, const Sw
2336 }2349 }
23372350
2338 // This is necessary if the last switch case "falls through" the end of the switch block2351 // This is necessary if the last switch case "falls through" the end of the switch block
2339 block_scope->node->data.block.statements.append(trans_create_node(c, NodeTypeBreak));2352 block_scope->node->data.block.statements.append(trans_create_node_goto(c, end_label_name));
23402353
2341 return while_scope->node;2354 block_scope->node->data.block.statements.append(trans_create_node_label(c, end_label_name));
2355
2356 return block_scope->node;
2342}2357}
23432358
2344static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,2359static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStmt *stmt, AstNode **out_node,
...@@ -2365,18 +2380,13 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStm...@@ -2365,18 +2380,13 @@ static int trans_switch_case(Context *c, TransScope *parent_scope, const CaseStm
2365 return ErrorUnexpected;2380 return ErrorUnexpected;
2366 prong_node->data.switch_prong.items.append(item_node);2381 prong_node->data.switch_prong.items.append(item_node);
23672382
2368 AstNode *goto_node = trans_create_node(c, NodeTypeGoto);2383 prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name);
2369 goto_node->data.goto_expr.name = label_name;
2370 prong_node->data.switch_prong.expr = goto_node;
23712384
2372 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);2385 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
2373 }2386 }
23742387
2375 AstNode *label_node = trans_create_node(c, NodeTypeLabel);
2376 label_node->data.label.name = label_name;
2377
2378 TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);2388 TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
2379 scope_block->node->data.block.statements.append(label_node);2389 scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name));
23802390
2381 AstNode *sub_stmt_node;2391 AstNode *sub_stmt_node;
2382 TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);2392 TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
...@@ -2399,23 +2409,19 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const Defa...@@ -2399,23 +2409,19 @@ static int trans_switch_default(Context *c, TransScope *parent_scope, const Defa
23992409
2400 Buf *label_name = buf_sprintf("default");2410 Buf *label_name = buf_sprintf("default");
24012411
2402 AstNode *label_node = trans_create_node(c, NodeTypeLabel);
2403 label_node->data.label.name = label_name;
2404
2405 {2412 {
2406 // Add the prong2413 // Add the prong
2407 AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);2414 AstNode *prong_node = trans_create_node(c, NodeTypeSwitchProng);
24082415
2409 AstNode *goto_node = trans_create_node(c, NodeTypeGoto);2416 prong_node->data.switch_prong.expr = trans_create_node_goto(c, label_name);
2410 goto_node->data.goto_expr.name = label_name;
2411 prong_node->data.switch_prong.expr = goto_node;
24122417
2413 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);2418 switch_scope->switch_node->data.switch_expr.prongs.append(prong_node);
2414 switch_scope->found_default = true;2419 switch_scope->found_default = true;
2415 }2420 }
24162421
2417 TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);2422 TransScopeBlock *scope_block = trans_scope_block_find(parent_scope);
2418 scope_block->node->data.block.statements.append(label_node);2423 scope_block->node->data.block.statements.append(trans_create_node_label(c, label_name));
2424
24192425
2420 AstNode *sub_stmt_node;2426 AstNode *sub_stmt_node;
2421 TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);2427 TransScope *new_scope = trans_stmt(c, parent_scope, stmt->getSubStmt(), &sub_stmt_node);
...@@ -2500,7 +2506,17 @@ static AstNode *trans_string_literal(Context *c, TransScope *scope, const String...@@ -2500,7 +2506,17 @@ static AstNode *trans_string_literal(Context *c, TransScope *scope, const String
2500}2506}
25012507
2502static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) {2508static AstNode *trans_break_stmt(Context *c, TransScope *scope, const BreakStmt *stmt) {
2503 return trans_create_node(c, NodeTypeBreak);2509 TransScope *cur_scope = scope;
2510 while (cur_scope != nullptr) {
2511 if (cur_scope->id == TransScopeIdWhile) {
2512 return trans_create_node(c, NodeTypeBreak);
2513 } else if (cur_scope->id == TransScopeIdSwitch) {
2514 TransScopeSwitch *switch_scope = (TransScopeSwitch *)cur_scope;
2515 return trans_create_node_goto(c, switch_scope->end_label_name);
2516 }
2517 cur_scope = cur_scope->parent;
2518 }
2519 zig_unreachable();
2504}2520}
25052521
2506static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) {2522static AstNode *trans_continue_stmt(Context *c, TransScope *scope, const ContinueStmt *stmt) {
test/translate_c.zig+4-3
...@@ -1019,7 +1019,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1019,7 +1019,7 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1019 ,1019 ,
1020 \\fn foo(_arg_x: c_int) -> c_int {1020 \\fn foo(_arg_x: c_int) -> c_int {
1021 \\ var x = _arg_x;1021 \\ var x = _arg_x;
1022 \\ while (true) {1022 \\ {
1023 \\ switch (x) {1023 \\ switch (x) {
1024 \\ 1 => goto case_0,1024 \\ 1 => goto case_0,
1025 \\ 2 => goto case_1,1025 \\ 2 => goto case_1,
...@@ -1030,13 +1030,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -1030,13 +1030,14 @@ pub fn addCases(cases: &tests.TranslateCContext) {
1030 \\ case_0:1030 \\ case_0:
1031 \\ x += 1;1031 \\ x += 1;
1032 \\ case_1:1032 \\ case_1:
1033 \\ break;1033 \\ goto end;
1034 \\ case_2:1034 \\ case_2:
1035 \\ case_3:1035 \\ case_3:
1036 \\ return x + 1;1036 \\ return x + 1;
1037 \\ default:1037 \\ default:
1038 \\ return 10;1038 \\ return 10;
1039 \\ break;1039 \\ goto end;
1040 \\ end:
1040 \\ };1041 \\ };
1041 \\ return x + 13;1042 \\ return x + 13;
1042 \\}1043 \\}