diff --git a/src/ast_render.cpp b/src/ast_render.cpp index 4f4dc1decd..d6a23e5f85 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -584,12 +584,15 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { PrefixOp op = node->data.prefix_op_expr.prefix_op; fprintf(ar->f, "%s", prefix_op_str(op)); - render_node_ungrouped(ar, node->data.prefix_op_expr.primary_expr); + AstNode *child_node = node->data.prefix_op_expr.primary_expr; + bool new_grouped = child_node->type == NodeTypePrefixOpExpr || child_node->type == NodeTypeAddrOfExpr; + render_node_extra(ar, child_node, new_grouped); if (!grouped) fprintf(ar->f, ")"); break; } case NodeTypeAddrOfExpr: { + if (!grouped) fprintf(ar->f, "("); fprintf(ar->f, "&"); if (node->data.addr_of_expr.align_expr != nullptr) { fprintf(ar->f, "align("); @@ -617,6 +620,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { } render_node_ungrouped(ar, node->data.addr_of_expr.op_expr); + if (!grouped) fprintf(ar->f, ")"); break; } case NodeTypeFnCallExpr: @@ -625,7 +629,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "@"); } AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr); + bool grouped = (fn_ref_node->type != NodeTypePrefixOpExpr && fn_ref_node->type != NodeTypeAddrOfExpr); render_node_extra(ar, fn_ref_node, grouped); fprintf(ar->f, "("); for (size_t i = 0; i < node->data.fn_call_expr.params.length; i += 1) { diff --git a/src/c_tokenizer.cpp b/src/c_tokenizer.cpp index 6be2cf991e..3746cf5853 100644 --- a/src/c_tokenizer.cpp +++ b/src/c_tokenizer.cpp @@ -121,6 +121,9 @@ static void begin_token(CTokenize *ctok, CTokId id) { case CTokIdRParen: case CTokIdEOF: case CTokIdDot: + case CTokIdAsterisk: + case CTokIdBang: + case CTokIdTilde: break; } } @@ -228,10 +231,22 @@ void tokenize_c_macro(CTokenize *ctok, const uint8_t *c) { begin_token(ctok, CTokIdRParen); end_token(ctok); break; + case '*': + begin_token(ctok, CTokIdAsterisk); + end_token(ctok); + break; case '-': begin_token(ctok, CTokIdMinus); end_token(ctok); break; + case '!': + begin_token(ctok, CTokIdBang); + end_token(ctok); + break; + case '~': + begin_token(ctok, CTokIdTilde); + end_token(ctok); + break; default: return mark_error(ctok); } diff --git a/src/c_tokenizer.hpp b/src/c_tokenizer.hpp index a3df2b94af..d7c9e53bcf 100644 --- a/src/c_tokenizer.hpp +++ b/src/c_tokenizer.hpp @@ -22,6 +22,9 @@ enum CTokId { CTokIdRParen, CTokIdEOF, CTokIdDot, + CTokIdAsterisk, + CTokIdBang, + CTokIdTilde, }; enum CNumLitSuffix { diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 5082c37a61..f8f5b5ba62 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -4000,6 +4000,10 @@ static void render_macros(Context *c) { } } +static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i); +static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i); +static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i); + static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, bool negate) { CTok *tok = &ctok->tokens.at(*tok_i); if (tok->id == CTokIdNumLitInt) { @@ -4027,7 +4031,7 @@ static AstNode *parse_ctok_num_lit(Context *c, CTokenize *ctok, size_t *tok_i, b return nullptr; } -static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { +static AstNode *parse_ctok_primary_expr(Context *c, CTokenize *ctok, size_t *tok_i) { CTok *tok = &ctok->tokens.at(*tok_i); switch (tok->id) { case CTokIdCharLit: @@ -4044,55 +4048,110 @@ static AstNode *parse_ctok(Context *c, CTokenize *ctok, size_t *tok_i) { return parse_ctok_num_lit(c, ctok, tok_i, false); case CTokIdSymbol: { - bool need_symbol = false; - CTokId curr_id = CTokIdSymbol; + *tok_i += 1; Buf *symbol_name = buf_create_from_buf(&tok->data.symbol); - AstNode *curr_node = trans_create_node_symbol(c, symbol_name); - AstNode *parent_node = curr_node; - do { - *tok_i += 1; - CTok* curr_tok = &ctok->tokens.at(*tok_i); - if (need_symbol) { - if (curr_tok->id == CTokIdSymbol) { - symbol_name = buf_create_from_buf(&curr_tok->data.symbol); - curr_node = trans_create_node_field_access(c, parent_node, buf_create_from_buf(symbol_name)); - parent_node = curr_node; - need_symbol = false; - } else { - return nullptr; - } - } else { - if (curr_tok->id == CTokIdDot) { - need_symbol = true; - continue; - } else { - break; - } - } - } while (curr_id != CTokIdEOF); - return curr_node; + return trans_create_node_symbol(c, symbol_name); } case CTokIdLParen: { *tok_i += 1; - AstNode *inner_node = parse_ctok(c, ctok, tok_i); + AstNode *inner_node = parse_ctok_expr(c, ctok, tok_i); + if (inner_node == nullptr) { + return nullptr; + } CTok *next_tok = &ctok->tokens.at(*tok_i); - if (next_tok->id != CTokIdRParen) { + if (next_tok->id == CTokIdRParen) { + *tok_i += 1; + return inner_node; + } + + AstNode *node_to_cast = parse_ctok_expr(c, ctok, tok_i); + if (node_to_cast == nullptr) { + return nullptr; + } + + CTok *next_tok2 = &ctok->tokens.at(*tok_i); + if (next_tok2->id != CTokIdRParen) { return nullptr; } *tok_i += 1; - return inner_node; + + if (inner_node->type == NodeTypeAddrOfExpr) { + AstNode *call_node = trans_create_node_builtin_fn_call_str(c, "ptrCast"); + call_node->data.fn_call_expr.params.append(inner_node); + call_node->data.fn_call_expr.params.append(node_to_cast); + return call_node; + } else { + return trans_create_node_cast(c, inner_node, node_to_cast); + } } case CTokIdDot: case CTokIdEOF: case CTokIdRParen: + case CTokIdAsterisk: + case CTokIdBang: + case CTokIdTilde: // not able to make sense of this return nullptr; } zig_unreachable(); } +static AstNode *parse_ctok_expr(Context *c, CTokenize *ctok, size_t *tok_i) { + return parse_ctok_prefix_op_expr(c, ctok, tok_i); +} + +static AstNode *parse_ctok_suffix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { + AstNode *node = parse_ctok_primary_expr(c, ctok, tok_i); + if (node == nullptr) + return nullptr; + + while (true) { + CTok *first_tok = &ctok->tokens.at(*tok_i); + if (first_tok->id == CTokIdDot) { + *tok_i += 1; + + CTok *name_tok = &ctok->tokens.at(*tok_i); + if (name_tok->id != CTokIdSymbol) { + return nullptr; + } + *tok_i += 1; + + node = trans_create_node_field_access(c, node, buf_create_from_buf(&name_tok->data.symbol)); + } else if (first_tok->id == CTokIdAsterisk) { + *tok_i += 1; + + node = trans_create_node_addr_of(c, false, false, node); + } else { + return node; + } + } +} + +static PrefixOp ctok_to_prefix_op(CTok *token) { + switch (token->id) { + case CTokIdBang: return PrefixOpBoolNot; + case CTokIdMinus: return PrefixOpNegation; + case CTokIdTilde: return PrefixOpBinNot; + case CTokIdAsterisk: return PrefixOpDereference; + default: return PrefixOpInvalid; + } +} +static AstNode *parse_ctok_prefix_op_expr(Context *c, CTokenize *ctok, size_t *tok_i) { + CTok *op_tok = &ctok->tokens.at(*tok_i); + PrefixOp prefix_op = ctok_to_prefix_op(op_tok); + if (prefix_op == PrefixOpInvalid) { + return parse_ctok_suffix_op_expr(c, ctok, tok_i); + } + *tok_i += 1; + + AstNode *prefix_op_expr = parse_ctok_prefix_op_expr(c, ctok, tok_i); + if (prefix_op_expr == nullptr) + return nullptr; + return trans_create_node_prefix_op(c, prefix_op, prefix_op_expr); +} + static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *char_ptr) { tokenize_c_macro(ctok, (const uint8_t *)char_ptr); @@ -4105,7 +4164,7 @@ static void process_macro(Context *c, CTokenize *ctok, Buf *name, const char *ch assert(name_tok->id == CTokIdSymbol && buf_eql_buf(&name_tok->data.symbol, name)); tok_i += 1; - AstNode *result_node = parse_ctok(c, ctok, &tok_i); + AstNode *result_node = parse_ctok_suffix_op_expr(c, ctok, &tok_i); if (result_node == nullptr) { return; } diff --git a/test/translate_c.zig b/test/translate_c.zig index d4974109da..bbdd56db0d 100644 --- a/test/translate_c.zig +++ b/test/translate_c.zig @@ -902,7 +902,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\} , \\export fn foo(x: ?&c_int) { - \\ (*(??x)) = 1; + \\ (*??x) = 1; \\} ); @@ -930,7 +930,7 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\pub fn foo() -> c_int { \\ var x: c_int = 1234; \\ var ptr: ?&c_int = &x; - \\ return *(??ptr); + \\ return *??ptr; \\} ); @@ -1188,4 +1188,10 @@ pub fn addCases(cases: &tests.TranslateCContext) { \\ const v2: &const u8 = c"2.2.2"; \\} ); + + cases.add("macro pointer cast", + \\#define NRF_GPIO ((NRF_GPIO_Type *) NRF_GPIO_BASE) + , + \\pub const NRF_GPIO = @ptrCast(&NRF_GPIO_Type, NRF_GPIO_BASE); + ); }