mirror of
https://github.com/ziglang/zig.git
synced 2025-01-07 10:45:17 +00:00
translate-c: support pre increment and decrement operators
This commit is contained in:
parent
741504862c
commit
68312afcdf
@ -1524,47 +1524,93 @@ static AstNode *trans_create_post_crement(Context *c, bool result_used, AstNode
|
|||||||
trans_expr(c, true, block, op_expr, TransLValue),
|
trans_expr(c, true, block, op_expr, TransLValue),
|
||||||
assign_op,
|
assign_op,
|
||||||
trans_create_node_unsigned(c, 1));
|
trans_create_node_unsigned(c, 1));
|
||||||
} else {
|
}
|
||||||
// worst case
|
// worst case
|
||||||
// c: expr++
|
// c: expr++
|
||||||
// zig: {
|
// zig: {
|
||||||
// zig: const _ref = &expr;
|
// zig: const _ref = &expr;
|
||||||
// zig: const _tmp = *_ref;
|
// zig: const _tmp = *_ref;
|
||||||
// zig: *_ref += 1;
|
// zig: *_ref += 1;
|
||||||
// zig: _tmp
|
// zig: _tmp
|
||||||
// zig: }
|
// zig: }
|
||||||
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
|
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
|
||||||
|
|
||||||
// const _ref = &expr;
|
// const _ref = &expr;
|
||||||
AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
|
AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
|
||||||
if (expr == nullptr) return nullptr;
|
if (expr == nullptr) return nullptr;
|
||||||
AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
|
AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
|
||||||
// TODO: avoid name collisions with generated variable names
|
// TODO: avoid name collisions with generated variable names
|
||||||
Buf* ref_var_name = buf_create_from_str("_ref");
|
Buf* ref_var_name = buf_create_from_str("_ref");
|
||||||
AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
|
AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
|
||||||
child_block->data.block.statements.append(ref_var_decl);
|
child_block->data.block.statements.append(ref_var_decl);
|
||||||
|
|
||||||
// const _tmp = *_ref;
|
// const _tmp = *_ref;
|
||||||
Buf* tmp_var_name = buf_create_from_str("_tmp");
|
Buf* tmp_var_name = buf_create_from_str("_tmp");
|
||||||
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
|
AstNode *tmp_var_decl = trans_create_node_var_decl_local(c, true, tmp_var_name, nullptr,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
trans_create_node_symbol(c, ref_var_name)));
|
trans_create_node_symbol(c, ref_var_name)));
|
||||||
child_block->data.block.statements.append(tmp_var_decl);
|
child_block->data.block.statements.append(tmp_var_decl);
|
||||||
|
|
||||||
// *_ref += 1;
|
// *_ref += 1;
|
||||||
AstNode *assign_statement = trans_create_node_bin_op(c,
|
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||||
trans_create_node_prefix_op(c, PrefixOpDereference,
|
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
trans_create_node_symbol(c, ref_var_name)),
|
trans_create_node_symbol(c, ref_var_name)),
|
||||||
|
assign_op,
|
||||||
|
trans_create_node_unsigned(c, 1));
|
||||||
|
child_block->data.block.statements.append(assign_statement);
|
||||||
|
|
||||||
|
// _tmp
|
||||||
|
child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
|
||||||
|
child_block->data.block.last_statement_is_result_expression = true;
|
||||||
|
|
||||||
|
return child_block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static AstNode *trans_create_pre_crement(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt, BinOpType assign_op) {
|
||||||
|
Expr *op_expr = stmt->getSubExpr();
|
||||||
|
|
||||||
|
if (!result_used) {
|
||||||
|
// common case
|
||||||
|
// c: ++expr
|
||||||
|
// zig: expr += 1
|
||||||
|
return trans_create_node_bin_op(c,
|
||||||
|
trans_expr(c, true, block, op_expr, TransLValue),
|
||||||
assign_op,
|
assign_op,
|
||||||
trans_create_node_unsigned(c, 1));
|
trans_create_node_unsigned(c, 1));
|
||||||
child_block->data.block.statements.append(assign_statement);
|
|
||||||
|
|
||||||
// _tmp
|
|
||||||
child_block->data.block.statements.append(trans_create_node_symbol(c, tmp_var_name));
|
|
||||||
child_block->data.block.last_statement_is_result_expression = true;
|
|
||||||
|
|
||||||
return child_block;
|
|
||||||
}
|
}
|
||||||
|
// worst case
|
||||||
|
// c: ++expr
|
||||||
|
// zig: {
|
||||||
|
// zig: const _ref = &expr;
|
||||||
|
// zig: *_ref += 1;
|
||||||
|
// zig: *_ref
|
||||||
|
// zig: }
|
||||||
|
AstNode *child_block = trans_create_node(c, NodeTypeBlock);
|
||||||
|
|
||||||
|
// const _ref = &expr;
|
||||||
|
AstNode *expr = trans_expr(c, true, child_block, op_expr, TransLValue);
|
||||||
|
if (expr == nullptr) return nullptr;
|
||||||
|
AstNode *addr_of_expr = trans_create_node_addr_of(c, false, false, expr);
|
||||||
|
// TODO: avoid name collisions with generated variable names
|
||||||
|
Buf* ref_var_name = buf_create_from_str("_ref");
|
||||||
|
AstNode *ref_var_decl = trans_create_node_var_decl_local(c, true, ref_var_name, nullptr, addr_of_expr);
|
||||||
|
child_block->data.block.statements.append(ref_var_decl);
|
||||||
|
|
||||||
|
// *_ref += 1;
|
||||||
|
AstNode *assign_statement = trans_create_node_bin_op(c,
|
||||||
|
trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
|
trans_create_node_symbol(c, ref_var_name)),
|
||||||
|
assign_op,
|
||||||
|
trans_create_node_unsigned(c, 1));
|
||||||
|
child_block->data.block.statements.append(assign_statement);
|
||||||
|
|
||||||
|
// *_ref
|
||||||
|
AstNode *deref_expr = trans_create_node_prefix_op(c, PrefixOpDereference,
|
||||||
|
trans_create_node_symbol(c, ref_var_name));
|
||||||
|
child_block->data.block.statements.append(deref_expr);
|
||||||
|
child_block->data.block.last_statement_is_result_expression = true;
|
||||||
|
|
||||||
|
return child_block;
|
||||||
}
|
}
|
||||||
|
|
||||||
static AstNode *trans_unary_operator(Context *c, bool result_used, AstNode *block, UnaryOperator *stmt) {
|
static 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
|
|||||||
else
|
else
|
||||||
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
|
return trans_create_post_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
|
||||||
case UO_PreInc:
|
case UO_PreInc:
|
||||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreInc");
|
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
|
||||||
return nullptr;
|
return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignPlusWrap);
|
||||||
|
else
|
||||||
|
return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignPlus);
|
||||||
case UO_PreDec:
|
case UO_PreDec:
|
||||||
emit_warning(c, stmt->getLocStart(), "TODO handle C translation UO_PreDec");
|
if (qual_type_has_wrapping_overflow(c, stmt->getType()))
|
||||||
return nullptr;
|
return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignMinusWrap);
|
||||||
|
else
|
||||||
|
return trans_create_pre_crement(c, result_used, block, stmt, BinOpTypeAssignMinus);
|
||||||
case UO_AddrOf:
|
case UO_AddrOf:
|
||||||
{
|
{
|
||||||
AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue);
|
AstNode *value_node = trans_expr(c, result_used, block, stmt->getSubExpr(), TransLValue);
|
||||||
|
@ -805,6 +805,50 @@ pub fn addCases(cases: &tests.TranslateCContext) {
|
|||||||
\\}
|
\\}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
cases.addC("pre increment/decrement",
|
||||||
|
\\void foo(void) {
|
||||||
|
\\ int i = 0;
|
||||||
|
\\ unsigned u = 0;
|
||||||
|
\\ ++i;
|
||||||
|
\\ --i;
|
||||||
|
\\ ++u;
|
||||||
|
\\ --u;
|
||||||
|
\\ i = ++i;
|
||||||
|
\\ i = --i;
|
||||||
|
\\ u = ++u;
|
||||||
|
\\ u = --u;
|
||||||
|
\\}
|
||||||
|
,
|
||||||
|
\\export fn foo() {
|
||||||
|
\\ var i: c_int = 0;
|
||||||
|
\\ var u: c_uint = c_uint(0);
|
||||||
|
\\ i += 1;
|
||||||
|
\\ i -= 1;
|
||||||
|
\\ u +%= 1;
|
||||||
|
\\ u -%= 1;
|
||||||
|
\\ i = {
|
||||||
|
\\ const _ref = &i;
|
||||||
|
\\ (*_ref) += 1;
|
||||||
|
\\ *_ref
|
||||||
|
\\ };
|
||||||
|
\\ i = {
|
||||||
|
\\ const _ref = &i;
|
||||||
|
\\ (*_ref) -= 1;
|
||||||
|
\\ *_ref
|
||||||
|
\\ };
|
||||||
|
\\ u = {
|
||||||
|
\\ const _ref = &u;
|
||||||
|
\\ (*_ref) +%= 1;
|
||||||
|
\\ *_ref
|
||||||
|
\\ };
|
||||||
|
\\ u = {
|
||||||
|
\\ const _ref = &u;
|
||||||
|
\\ (*_ref) -%= 1;
|
||||||
|
\\ *_ref
|
||||||
|
\\ };
|
||||||
|
\\}
|
||||||
|
);
|
||||||
|
|
||||||
cases.addC("do loop",
|
cases.addC("do loop",
|
||||||
\\void foo(void) {
|
\\void foo(void) {
|
||||||
\\ int a = 2;
|
\\ int a = 2;
|
||||||
|
Loading…
Reference in New Issue
Block a user