authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-24 16:36:39-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-11-24 16:36:39-05:00
log68312afcdf5a75ddc95dc21cb2f610780c0b69a6
tree9e13c8b8121e3e0bc3983dce730308076344df5c
parent741504862c7094dc91d3bf4c4da58e9236a7633a

translate-c: support pre increment and decrement operators


2 files changed, 132 insertions(+), 38 deletions(-)

src/translate_c.cpp+88-38
...@@ -1524,47 +1524,93 @@ static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode...@@ -1524,47 +1524,93 @@ static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode
1524 trans_expr(c, true, block, op_expr, TransLValue),1524 trans_expr(c, true, block, op_expr, TransLValue),
1525 assign_op,1525 assign_op,
1526 trans_create_node_unsigned(c, 1));1526 trans_create_node_unsigned(c, 1));
1527 } else {1527 }
1528 // worst case1528 // worst case
1529 // c: expr++1529 // c: expr++
1530 // zig: {1530 // zig: {
1531 // zig: const _ref = &expr;1531 // zig: const _ref = &expr;
1532 // zig: const _tmp = *_ref;1532 // zig: const _tmp = *_ref;
1533 // zig: *_ref += 1;1533 // zig: *_ref += 1;
1534 // zig: _tmp1534 // zig: _tmp
1535 // zig: }1535 // zig: }
1536 AstNode *child_block = trans_create_node(c, NodeTypeBlock);1536 AstNode *child_block = trans_create_node(c, NodeTypeBlock);
15371537
1538 // const _ref = &expr;1538 // const _ref = &expr;
1539 AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);1539 AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
1540 if (expr == nullptr) return nullptr;1540 if (expr == nullptr) return nullptr;
1541 AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);1541 AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
1542 // TODO: avoid name collisions with generated variable names1542 // TODO: avoid name collisions with generated variable names
1543 Buf* ref_var_name = buf_create_from_str("_ref");1543 Buf* ref_var_name = buf_create_from_str("_ref");
1544 AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);1544 AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
1545 child_block->data.block.statements.append(ref_var_decl);1545 child_block->data.block.statements.append(ref_var_decl);
1546
1547 // const _tmp = *_ref;
1548 Buf* tmp_var_name = buf_create_from_str("_tmp");
1549 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
1550 trans_create_node_prefix_op(c, PrefixOpDereference,
1551 trans_create_node_symbol(c, ref_var_name)));
1552 child_block->data.block.statements.append(tmp_var_decl);
1553
1554 // *_ref += 1;
1555 AstNode *assign_statement = trans_create_node_bin_op(c,
1556 trans_create_node_prefix_op(c, PrefixOpDereference,
1557 trans_create_node_symbol(c, ref_var_name)),
1558 assign_op,
1559 trans_create_node_unsigned(c, 1));
1560 child_block->data.block.statements.append(assign_statement);
1561
1562 // _tmp
1563 child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
1564 child_block->data.block.last_statement_is_result_expression = true;
15461565
1547 // const _tmp = *_ref;1566 return child_block;
1548 Buf* tmp_var_name = buf_create_from_str("_tmp");1567}
1549 AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
1550 trans_create_node_prefix_op(c, PrefixOpDereference,
1551 trans_create_node_symbol(c, ref_var_name)));
1552 child_block->data.block.statements.append(tmp_var_decl);
15531568
1554 // *_ref += 1;1569static AstNode *trans_create_pre_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
1555 AstNode *assign_statement = trans_create_node_bin_op(c,1570 Expr *op_expr = stmt->getSubExpr();
1556 trans_create_node_prefix_op(c, PrefixOpDereference,1571
1557 trans_create_node_symbol(c, ref_var_name)),1572 if (!result_used) {
1573 // common case
1574 // c: ++expr
1575 // zig: expr += 1
1576 return trans_create_node_bin_op(c,
1577 trans_expr(c, true, block, op_expr, TransLValue),
1558 assign_op,1578 assign_op,
1559 trans_create_node_unsigned(c, 1));1579 trans_create_node_unsigned(c, 1));
1560 child_block->data.block.statements.append(assign_statement);1580 }
1581 // worst case
1582 // c: ++expr
1583 // zig: {
1584 // zig: const _ref = &expr;
1585 // zig: *_ref += 1;
1586 // zig: *_ref
1587 // zig: }
1588 AstNode *child_block = trans_create_node(c, NodeTypeBlock);
15611589
1562 // _tmp1590 // const _ref = &expr;
1563 child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));1591 AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
1564 child_block->data.block.last_statement_is_result_expression = true;1592 if (expr == nullptr) return nullptr;
1593 AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
1594 // TODO: avoid name collisions with generated variable names
1595 Buf* ref_var_name = buf_create_from_str("_ref");
1596 AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
1597 child_block->data.block.statements.append(ref_var_decl);
1598
1599 // *_ref += 1;
1600 AstNode *assign_statement = trans_create_node_bin_op(c,
1601 trans_create_node_prefix_op(c, PrefixOpDereference,
1602 trans_create_node_symbol(c, ref_var_name)),
1603 assign_op,
1604 trans_create_node_unsigned(c, 1));
1605 child_block->data.block.statements.append(assign_statement);
1606
1607 // *_ref
1608 AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
1609 trans_create_node_symbol(c, ref_var_name));
1610 child_block->data.block.statements.append(deref_expr);
1611 child_block->data.block.last_statement_is_result_expression = true;
15651612
1566 return child_block;1613 return child_block;
1567 }
1568}1614}
15691615
1570static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {1616static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
...@@ -1580,11 +1626,15 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc...@@ -1580,11 +1626,15 @@ static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *bloc
1580 else1626 else
1581 return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);1627 return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
1582 case UO_PreInc:1628 case UO_PreInc:
1583 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");1629 if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1584 return nullptr;1630 return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
1631 else
1632 return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
1585 case UO_PreDec:1633 case UO_PreDec:
1586 emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec");1634 if (qual_type_has_wrapping_overflow(c, stmt->getType()))
1587 return nullptr;1635 return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
1636 else
1637 return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
1588 case UO_AddrOf:1638 case UO_AddrOf:
1589 {1639 {
1590 AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue);1640 AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue);
test/translate_c.zig+44
...@@ -805,6 +805,50 @@ pub fn addCases(cases: &tests.TranslateCContext) {...@@ -805,6 +805,50 @@ pub fn addCases(cases: &tests.TranslateCContext) {
805 \\}805 \\}
806 );806 );
807807
808 cases.addC("pre increment/decrement",
809 \\void foo(void) {
810 \\ int i = 0;
811 \\ unsigned u = 0;
812 \\ ++i;
813 \\ --i;
814 \\ ++u;
815 \\ --u;
816 \\ i = ++i;
817 \\ i = --i;
818 \\ u = ++u;
819 \\ u = --u;
820 \\}
821 ,
822 \\export fn foo() {
823 \\ var i: c_int = 0;
824 \\ var u: c_uint = c_uint(0);
825 \\ i += 1;
826 \\ i -= 1;
827 \\ u +%= 1;
828 \\ u -%= 1;
829 \\ i = {
830 \\ const _ref = &i;
831 \\ (*_ref) += 1;
832 \\ *_ref
833 \\ };
834 \\ i = {
835 \\ const _ref = &i;
836 \\ (*_ref) -= 1;
837 \\ *_ref
838 \\ };
839 \\ u = {
840 \\ const _ref = &u;
841 \\ (*_ref) +%= 1;
842 \\ *_ref
843 \\ };
844 \\ u = {
845 \\ const _ref = &u;
846 \\ (*_ref) -%= 1;
847 \\ *_ref
848 \\ };
849 \\}
850 );
851
808 cases.addC("do loop",852 cases.addC("do loop",
809 \\void foo(void) {853 \\void foo(void) {
810 \\ int a = 2;854 \\ int a = 2;